Compare commits

...

156 Commits

Author SHA1 Message Date
Felix Fontein
31579ed237 Release 1.9.25. 2024-05-20 11:30:53 +02:00
Felix Fontein
b7159e0979 Disable CentOS 7 tests on 2.9 and 2.11. 2024-05-11 22:27:08 +02:00
patchback[bot]
a92d900552 Pass codecov token to ansible-test-gh-action. (#755) (#756)
(cherry picked from commit 65ea02a73d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2024-05-11 21:47:33 +02:00
patchback[bot]
29ed12e7fd ecs_certificate: allow to request renewal without csr (#740) (#752)
* renew request CSR validation

* Create 740-ecs_certificate-renewal-without-csr

* Rename 740-ecs_certificate-renewal-without-csr to 740-ecs_certificate-renewal-without-csr.yml

---------

Co-authored-by: flovecchio <flovecchio@sorint.com>
(cherry picked from commit 29ac3cbe81)

Co-authored-by: francescolovecchio <francescolovecchio97@gmail.com>
2024-05-09 21:31:06 +02:00
Felix Fontein
0ef6494ad2 crypto.math module utils: add some tests, fix quick_is_not_prime() for small primes (#733) (#734)
* Fix quick_is_not_prime() for small primes. Add some tests.

* Fix return value of convert_int_to_bytes(0, 0) on Python 2.

* Add some more test cases.

* Simplify the changelog and point out that these errors only happen for cases not happening in regular use.

(cherry picked from commit 0c62837296)
2024-04-29 12:03:41 +02:00
Felix Fontein
ec7b6b4285 macOS 12.0 no longer seems to run in CI. 2024-02-11 13:43:54 +01:00
Felix Fontein
4f6f7410f2 Add MarkDown changelog and use it by default. (#709) 2024-02-09 13:08:17 +01:00
Felix Fontein
ea34992f03 Next expected release is 1.9.25. 2024-01-27 12:30:29 +01:00
Felix Fontein
9d59389fc0 Release 1.9.24. 2024-01-27 10:43:40 +01:00
Felix Fontein
1d26ee66ea [stable-1] x509_certificate: handle unexpected error, fix test (#704)
* Handle unexpected error.

* Increase certificate key size on Darwin.

* Add changelog fragment.
2024-01-26 21:58:12 +01:00
Felix Fontein
642d6872d1 [stable-1] Disable consistency checking of RSA keys for cryptography 42.0.0 which no longer gives access to the required function (#703)
* Disable consistency checking of RSA keys for cryptography 42.0.0 which no longer gives access to the required function. (#702)

(cherry picked from commit 87af1f2761)

* Adjust tests to ignore key_is_consistent.
2024-01-26 19:27:40 +01:00
Felix Fontein
940a1aabd9 Disable certificate version 2 test for pyOpenSSL 24.0.0+. 2024-01-26 14:20:40 +01:00
Felix Fontein
8a8faa83e4 Prepare 1.9.24 release. 2024-01-25 23:49:23 +01:00
patchback[bot]
14d7e75faf Fix openssl_dhparam. (#698) (#699)
(cherry picked from commit b57aa4a2ca)

Co-authored-by: Felix Fontein <felix@fontein.de>
2024-01-25 23:47:44 +01:00
Felix Fontein
4f27ae4011 Simplifiy workflows. (#696)
(cherry picked from commit 0bc15598d7)
2024-01-21 15:23:43 +01:00
patchback[bot]
c9f2958fe4 Use import galaxy workflow from https://github.com/ansible-collections/community.docker/pull/754. (#694) (#695)
(cherry picked from commit fb3f68ca96)

Co-authored-by: Felix Fontein <felix@fontein.de>
2024-01-13 23:13:36 +01:00
Felix Fontein
f9f8456ee9 Remove FreeBSD 12.4 from CI. (#691) 2023-12-31 15:36:48 +01:00
patchback[bot]
7246b7e752 Add new error message. (#688) (#689)
(cherry picked from commit 033b456b7a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-12-20 13:50:17 +01:00
Felix Fontein
329e908e84 Deactivate FreeBSD 13.1 in CI. 2023-12-10 14:29:10 +01:00
patchback[bot]
d795facb29 Fix bad expressions in tests. (#677) (#678)
ci_complete

(cherry picked from commit 29cd0b3bde)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-11-29 06:53:36 +01:00
Felix Fontein
c5f29f85ce Stick to pre-semantic-markup version. 2023-11-12 14:20:01 +01:00
Felix Fontein
af119267cc Next expected release is 1.9.24. 2023-10-29 16:00:51 +01:00
Felix Fontein
9e367e1d42 Release 1.9.23. 2023-10-29 15:32:31 +01:00
Felix Fontein
cb747236d9 [stable-1] openssl_pkcs12: handle pyOpenSSL 23.3.0, which removed PKCS#12 support (#668)
* Handle pyOpenSSL 23.3.0, which removed PKCS#12 support (at least partially). (#666)

(cherry picked from commit d1299c11d6)

* Try to fix FreeBSD 13.1 failures in CI.
2023-10-28 22:13:20 +02:00
patchback[bot]
b73bd91783 Fix Galaxy URLs. (#658) (#659)
(cherry picked from commit 5f4fc95c50)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-09-30 22:48:50 +02:00
Felix Fontein
21632bf044 Bump FreeBSD versions on stable-2.13. (#650) 2023-08-15 07:14:35 +02:00
patchback[bot]
a836169da4 Bump AZP container. (#629) (#630)
(cherry picked from commit b40a1c54f7)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-06-24 16:29:51 +02:00
Felix Fontein
ce93a9a2db Next expected release is 1.9.23. 2023-06-15 13:25:53 +02:00
Felix Fontein
52407bd8d8 Release 1.9.22. 2023-06-15 13:01:33 +02:00
patchback[bot]
9ef079efab Fix example. (#620) (#621)
(cherry picked from commit a7e9bb7618)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-06-09 12:58:39 +02:00
Felix Fontein
afd2bd3bad Move ansible-core 2.12 to EOL CI (#609) (#610)
* https://github.com/ansible/ansible/pull/79734 has been merged and backported for all branches but stable-2.10 and stable-2.11.

* Move ansible-core 2.12 to EOL CI.

(cherry picked from commit 0d30a3793a)
2023-05-29 18:33:26 +02:00
Felix Fontein
022b011a90 Switch to Ansible Galaxy compatible requirements files for tests. (#607) (#608)
(cherry picked from commit e3bc22f7d5)
2023-05-21 14:38:13 +02:00
patchback[bot]
7a1494cbe4 Always generate a new key pair if the private key doesn't exist (#598) (#599)
* Always generate a new key pair if the private key doesn't exist (#597)

This commit updates `KeypairBackend._should_generate()` to first check
if the original private key named by the `path` argument exists, and
return True if it does not. This brings the code in line with
the documentation, which says that a new key will always be generated if
the key file doesn't already exist.

As an alternative to the approach implemented here, I also considered
only modifying the condition in the `fail` branch of the if statement,
but I thought that would not map as cleanly to the behavior specified in
the documentation, so doing it the way I did should make it easier to
check that the code is doing the right thing just by looking at it.
I also considered doing something to make the logic more similar to
`PrivateKeyBackend.needs_regeneration()` (the openssl version of this
functionality), because the two are supposed to be acting the same way,
but I thought that'd be going beyond the scope of just fixing this bug.
If it'd be useful to make both methods work the same way, someone can
refactor the code in a future commit.

* Test different regenerate values with nonexistent keys

This commit changes the test task that generates new keys to use each of
the different values for the `regenerate` argument, which will ensure
that the module is capable of generating a key when no previous key
exists regardless of the value of `regenerate`. Previously, the task
would always run with the `partial_idempotence` value, and that obscured
a bug (#597) that would occur when it was set to `fail`. The bug was
fixed in the previous commit.

(cherry picked from commit ce3299f106)

Co-authored-by: David Zaslavsky <diazona@ellipsix.net>
2023-05-01 21:34:10 +02:00
Felix Fontein
2b98c0b250 The next release will be 1.9.22. 2023-04-16 20:07:23 +02:00
Felix Fontein
f10504e95f Release 1.9.21. 2023-04-16 19:47:19 +02:00
patchback[bot]
7fbe649dc6 Do extra docs validation; explicitly disallow semantic markup in docs (#593) (#594)
* Do extra docs validation. Explicitly disallow semantic markup in docs.

* Forgot to add new requirement.

* Improve test.

* TEMP - make CI fail.

* Revert "TEMP - make CI fail."

This reverts commit a71b8901c1.

* Remove unnecessary import.

* Make sure ANSIBLE_COLLECTIONS_PATH is set.

* Make sure sanity tests from older Ansible versions don't complain.

(cherry picked from commit ceabef7e58)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-04-16 18:55:26 +02:00
Felix Fontein
11e7232bd6 For some reason some 2.9 tests were still running in AZP. 2023-04-09 14:27:39 +02:00
patchback[bot]
9fc27e74f8 Use curl instead of get_url on Python 2.6. (#585) (#586)
(cherry picked from commit 0829bc641e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-03-22 21:30:53 +01:00
patchback[bot]
1572c10384 fix(doc): privatekey_content docs were the same as privatekey_path (#583) (#584)
(cherry picked from commit b997773139)

Co-authored-by: Thomas Anderson <tnyeanderson@users.noreply.github.com>
2023-03-21 18:02:40 +01:00
Felix Fontein
553f3c2ee0 Cancel concurrent workflow runs in PRs.
(cherry picked from commit 5a3e21788d)
2023-02-23 09:57:25 +01:00
patchback[bot]
837733b4c2 Fix deprecation handling. (#572) (#573)
(cherry picked from commit 70c4585b88)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-02-09 16:25:26 +01:00
patchback[bot]
3468628f1f Fix acme_inspect tests. (#565) (#566)
(cherry picked from commit c6429eae4f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-01-23 06:41:21 +01:00
patchback[bot]
eee646b636 openssl_csr: fix bad tests, avoid accepting invalid crl_distribution_points records (#560) (#561)
* Improve error handling.

* Remove invalid tests.

* Add changelog fragment.

* Fix tests.

* Improve exception catching.

Co-authored-by: Kristian Heljas <11139388+kristianheljas@users.noreply.github.com>

* Prevent empty full_name.

* Fix condition. Make sure errors are caught.

* Add more checks.

Co-authored-by: Kristian Heljas <11139388+kristianheljas@users.noreply.github.com>
(cherry picked from commit ddfb18b609)

Co-authored-by: Felix Fontein <felix@fontein.de>
2023-01-02 17:28:28 +01:00
Felix Fontein
e78318c4cb Next release will be 1.9.21. 2023-01-01 08:52:43 +01:00
Felix Fontein
8ccab3ab80 Release 1.9.20. 2023-01-01 08:14:32 +01:00
patchback[bot]
e2ecd14d86 Fix crash when public key cannot be parsed. (#551) (#552)
(cherry picked from commit 5d24d04adf)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-12-28 20:53:02 +01:00
patchback[bot]
6f8131a628 Make sure that iteration_count=1000 is not used with algorithm=argon* (which is SLOW and takes around 10 minutes). (#546) (#547)
(cherry picked from commit 242c15bf4c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-12-20 20:16:20 +01:00
Felix Fontein
5761ca12b6 Disable broken CI platforms. (#469)
(cherry picked from commit f7bc3aa77c)
2022-12-20 07:24:19 +01:00
Felix Fontein
bfe181ac1f Move tests with EOL versions of Ansible from AZP to GHA. (#543) 2022-12-20 06:58:28 +01:00
Felix Fontein
f5632c27f4 [TEMP] Create temp remote directory in ~. (#504)
(cherry picked from commit d0d99c31b0)
2022-12-11 18:12:53 +01:00
Felix Fontein
6bec0b402c Be more precise about which private keys are supported in openssl_publickey. (#532)
(cherry picked from commit 1097371cf4)
2022-11-27 18:19:42 +01:00
Felix Fontein
b0262bf8f1 Prepare 1.9.20 release. 2022-11-01 21:14:17 +01:00
Felix Fontein
c57822b3b3 Release 1.9.19. 2022-11-01 20:53:52 +01:00
patchback[bot]
c313bbd83d Action plugin support code: ensure compatibility with newer versions of ansible-core (#515) (#516)
* Only access C.STRING_CONVERSION_ACTION for old ansible-base / Ansible versions.

* Always use self.__xxx instead of xxx directly.

(cherry picked from commit b3f589df62)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-09-23 07:33:48 +02:00
patchback[bot]
b9e8bb70eb Fix docs (#497) (#498)
* Fix docs.

* Fix YAML.

* Prevent crashes with older pyyaml versions.

(cherry picked from commit 2dafef1fab)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-08-04 20:17:55 +02:00
patchback[bot]
62da550c6c Fix ssh-agent tests (#493) (#494)
* Work around stupid ssh-agent output format.

* Workaround for Ansible 2.9.

* Old jinja2...

* Jinja2 on CentOS 6 is really annoying.

(cherry picked from commit e4ebca0945)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-07-22 14:00:53 +02:00
Felix Fontein
3d9fb17d17 Fix typo. 2022-07-09 13:54:52 +02:00
Felix Fontein
2fd7aa6de7 Prepare 1.9.19. 2022-07-09 13:51:12 +02:00
Felix Fontein
b78dd8d542 Release 1.9.18. 2022-07-09 13:17:40 +02:00
Felix Fontein
1df51621fa openssl_pkcs12: fix crash when trying to get non-existing other certificates (#487) (#488)
* Fix crash when trying to get non-existing other certificates.

* Add test.

(cherry picked from commit 9ed4526fee)
2022-07-07 22:53:36 +02:00
Felix Fontein
33703d15e2 Prepare 1.9.18 release. 2022-06-17 09:26:09 +02:00
Felix Fontein
b682c7a281 Release 1.9.17. 2022-06-17 08:23:20 +02:00
Felix Fontein
d393ea233e Add Apache 2.0 license for Apache 2.0 licensed parts. (#479) 2022-06-17 08:21:08 +02:00
patchback[bot]
563e3a2791 Fix ValueError: excluded_subtrees must be a non-empty list or None (#481) (#482)
(cherry picked from commit b29f238083)

Co-authored-by: Songmin Li <lisongmin@protonmail.com>
2022-06-17 08:02:49 +02:00
Felix Fontein
651f2b8f5d x509_crl: do not crash when signing with Ed25519 or Ed448 (#475) (#480)
* Do not crash when signing with Ed25519 or Ed448.

* Forgot replace.

(cherry picked from commit 297b44f24b)
2022-06-15 22:29:34 +02:00
patchback[bot]
077bcba377 Skip Ansible 2.9 coverage reporting with new AZP container. (#476) (#477)
ci_coverage

(cherry picked from commit 429ed5faa5)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-06-14 20:32:32 +00:00
patchback[bot]
9084df1e5c Bump AZP container version. (#472) (#474)
(cherry picked from commit b3029f75cd)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-06-13 21:58:14 +02:00
patchback[bot]
2bb6d7f49d Disable broken CI platforms. (#469) (#470)
(cherry picked from commit f7bc3aa77c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-06-06 09:36:44 +02:00
Felix Fontein
83cf13a483 Next expected release is 1.9.17. 2022-06-02 12:46:50 +02:00
Felix Fontein
1b22a88b80 Release 1.9.16. 2022-06-02 12:27:44 +02:00
patchback[bot]
252c1a7236 Add simplified_bsd.txt license file (#467) (#468)
* Add simplified_bsd.txt and adjust references.

* Add changelog.

(cherry picked from commit ccd66419f4)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-06-02 08:14:26 +02:00
Felix Fontein
7f371f6915 Update release summary for 1.9.16. 2022-06-02 07:48:31 +02:00
patchback[bot]
1ccd48efba Remove FreeBSD 12.1 from CI. The remote seems to be no longer working. (#459) (#461)
(cherry picked from commit fd0048827d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-05-20 15:33:08 +00:00
patchback[bot]
a4c077c388 certificate_complete_chain: do not stop execution on unsupported algorithm (#457) (#458)
* Do not stop execution on unsupported algorithm.

* Fix typo.

(cherry picked from commit c49102d688)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-05-20 12:47:59 +02:00
Felix Fontein
2b1e85c86c Next expected release is 1.9.16. 2022-05-16 12:52:21 +02:00
Felix Fontein
a68f119afe Release 1.9.15. 2022-05-16 12:26:27 +02:00
Felix Fontein
9ebf7d668f [stable-1] Add PSF-license.txt file (#455)
* Add PSF-license.txt file. (#453)

(cherry picked from commit 5664bfe4b6)

* Update with actual CPython 3.9.5 license. (#454)

(cherry picked from commit 7183596586)
2022-05-16 09:02:58 +02:00
Felix Fontein
4570c481ef Prepare 1.9.15 release. 2022-05-16 07:14:00 +02:00
Felix Fontein
5d56629d10 Prepare 1.9.15 release. 2022-05-09 20:52:41 +02:00
Felix Fontein
37c7100c8b Release 1.9.14. 2022-05-09 20:29:24 +02:00
Felix Fontein
35266bda0e Prepare 1.9.14 release. 2022-05-03 19:25:24 +02:00
Felix Fontein
6a90a43995 Fix stable-1 for new cryptography 37.0.0 release (#446)
* Fix empty check for openssl_pkcs12 tests.

* Prevent crash if PyOpenSSL cannot be imported because of an AttributeError.

* Add changelog fragment.

* Fix constraints file.

* Use Python 2.7 instead of 3.5 for 2.9 cloud tests (pip module is broken).

* Prevent upgrading cryptography on ansible-core 2.12's default container with Python 3.9.
2022-04-26 22:33:13 +02:00
Felix Fontein
096262b6f1 Fix crash in x509_crl when certificate issuer is specified (#441) (#442)
* Fix x509_crl certificate issuer issue.

* Add tests.

* Add changelog fragment.

(cherry picked from commit 9d03178b00)
2022-04-18 10:19:27 +02:00
patchback[bot]
03df636e5e Switch from antsibull to antsibull-docs. (#438) (#439)
(cherry picked from commit c7f581daad)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-04-10 10:58:54 +02:00
Felix Fontein
02bc9de560 On the 'default' image with Python 3.8, cryptography 2.8 is installed from the
system packages, but cryptography 36.0.1 is already present and shadows the
one from the system packages. Since PyOpenSSL is also installed from the system
packages, there is a version mismatch between the two. Temporarily disable the
Python 3.8 tests with the 'default' image on ansible-core 2.13 until this is
resolved, or the stable-1 branch is EOL (whatever comes first).
2022-04-03 15:08:55 +02:00
patchback[bot]
8fe0a2450e Replace antsibull-lint collection-docs with antsibull-docs lint-collection-docs. (#432) (#433)
(cherry picked from commit bc00c30faf)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-30 08:13:40 +02:00
Felix Fontein
d8bb99d547 Replace devel with stable-2.13 in stable-1 CI. (#424) 2022-03-29 06:19:54 +02:00
patchback[bot]
79f9ce437a openssh_* - catch and report top-level exceptions via fail_json (#417) (#418)
* ensure exceptions are properly reported

* adding changelog fragment

* applying review suggestions

* typo

* adding back exception msg

(cherry picked from commit 033bab7db1)

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>
2022-03-08 20:25:38 +01:00
Felix Fontein
6cb02818ef Next expected release is 1.9.14. 2022-03-04 08:06:24 +01:00
Felix Fontein
e94fb2dff2 Release 1.9.13. 2022-03-04 07:38:05 +01:00
Felix Fontein
14c39b1f99 Prepare 1.9.13 release. 2022-03-03 21:17:36 +01:00
patchback[bot]
6dafa5954e fixing public key return value docs (#412) (#414)
(cherry picked from commit 010f1a4d2d)

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>
2022-03-02 14:09:20 +01:00
patchback[bot]
da1dd21a9e Fix parsing of lsblk output. (#410) (#413)
(cherry picked from commit 0d4b3ed991)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-02 14:05:07 +01:00
Felix Fontein
011036b87f Next expected release is 1.9.13. 2022-02-21 22:22:36 +01:00
Felix Fontein
35ef2edb3f Release 1.9.12. 2022-02-21 21:48:14 +01:00
Felix Fontein
ebcf866891 Prepare 1.9.12 release. 2022-02-19 18:53:26 +01:00
Felix Fontein
60c6d87b05 [stable-1] x509_certificate: regenerate certificate on CA's subject change (#406)
* Regenerate certificate on CA's subject change. (#402)

(cherry picked from commit 3ebc132c03)

* Add fix for PyOpenSSL backend.

* x509_certificate: check existing certificate's signature for selfsigned and ownca provider (#407)

* Verify whether signature matches.

* Add changelog fragment.

* Forgot imports.

* Fix wrong name.

* Check whether the CA private key fits to the CA certificate. Use correct key in tests.

* Refactor code.

(cherry picked from commit 28729657ac)

* There doesn't seem a way to do this with pyOpenSSL.
2022-02-19 17:51:28 +00:00
patchback[bot]
2aa38fe247 certificate_complete_chain: handle duplicate intermediate subjects (#403) (#405)
* Allow multiple intermediate CAs to have same subject.

* Add tests.

* Fix test name.

* Don't use CN for SAN.

* Make a bit more compatible.

* Include jinja2 compat for CentOS 6.

(cherry picked from commit 11a14543c8)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-14 18:04:54 +01:00
Felix Fontein
d19faa1627 Next expected release is 1.9.12. 2022-02-05 21:45:27 +01:00
Felix Fontein
e910f299b9 Release 1.9.11. 2022-02-05 21:28:22 +01:00
Felix Fontein
2ebf26854e Prepare 1.9.11 release. 2022-02-05 20:19:18 +01:00
Andrew Pantuso
7ff067937a openssh_cert - fix full_idempotence for host certificates (#396) (#397)
* fixing host cert idempotence

* adding changelog fragment

(cherry picked from commit a307618872)
2022-02-05 10:00:07 +01:00
Felix Fontein
2727b74cc7 Next expected release is 1.9.11. 2022-02-01 06:18:36 +01:00
Felix Fontein
3bb9c5f9a7 Release 1.9.10. 2022-02-01 05:49:00 +01:00
patchback[bot]
5623590c77 Drop CentOS 8 from CI. (#393) (#394)
(cherry picked from commit 23226dce8f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-01 05:24:21 +01:00
Felix Fontein
29050913b3 Prepare 1.9.10 release. 2022-01-31 06:03:15 +01:00
patchback[bot]
aead2bf783 Set LANG and similar env variables to prevent translated cryptsetup output. (#388) (#390)
(cherry picked from commit ea2e45d63f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-30 21:57:31 +01:00
patchback[bot]
2aaae70372 [PR #387/5abfe8fc backport][stable-1] PyOpenSSL 22.0.0 no longer supports Python 2.7 (#389)
* PyOpenSSL 22.0.0 no longer supports Python 2.7. (#387)

(cherry picked from commit 5abfe8fca9)

* Do not install PyOpenSSL from PyPi if cryptography cannot be updated - at least on FreeBSD 13.0, latest PyOpenSSL requires a cryptography upgrade, which breaks CI.

* Revert "Do not install PyOpenSSL from PyPi if cryptography cannot be updated - at least on FreeBSD 13.0, latest PyOpenSSL requires a cryptography upgrade, which breaks CI."

This reverts commit 16f9145653.

* Try another approach.

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-30 15:23:29 +01:00
patchback[bot]
de29a258c6 Fix indentation of when in example. (#382) (#383)
(cherry picked from commit a467f036b1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-19 04:54:17 +00:00
patchback[bot]
8ca5b480e4 Update CI matrix for Remote Devel (#377) (#378)
* Update CI matrix for Remote Devel.

* Add Python info entries.

(cherry picked from commit cd5ed011a5)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-13 09:52:59 +01:00
Felix Fontein
f6ec785b0d Next expected release is 1.9.10. 2022-01-11 07:28:54 +01:00
Felix Fontein
4834c0cb4b Release 1.9.9. 2022-01-11 07:04:43 +01:00
patchback[bot]
1f0016c616 Fix comment. (#372) (#373)
(cherry picked from commit 1b0fcde862)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-06 15:10:40 +01:00
patchback[bot]
74e4be139f Use vendored copy of distutils.version. (#369) (#370)
(cherry picked from commit 46f39efc43)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-05 22:22:25 +01:00
patchback[bot]
b584336b62 Fix typo. (#367) (#368)
(cherry picked from commit 3e307fe062)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-05 20:36:01 +01:00
patchback[bot]
20b0d7a298 certificate_complete_chain: avoid infinite loops, and double roots when root certificate was already part of chain (#360) (#366)
* Avoid infinite loops, and double roots when root certificate was already part of chain.

* Refactor tests for readability.

(cherry picked from commit 6ee238d961)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-04 07:27:15 +01:00
patchback[bot]
5741f24aa9 Fix indentation in docs. (#364) (#365)
(cherry picked from commit f3e431912d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-03 21:47:20 +01:00
patchback[bot]
b5dfc9fc75 Improve changed / nonchanged validations by using new modules from community.internal_test_tools (#183) (#361)
* Use modules from internal_test_tools instead of stat workaround to check whether file actually changed.

* Properly add testing dependency.

(cherry picked from commit 471506c5d4)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-03 19:30:21 +01:00
patchback[bot]
4318e95618 Feature/rename test cases (#356) (#358)
* Name test tasks in a more explicite manner

* Space test + verification blocks apart

* Apply suggestions from code review

Co-authored-by: Jens Heinrich <github.com/JensHeinrich>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 2c05221d89)

Co-authored-by: Jens Heinrich <59469646+JensHeinrich@users.noreply.github.com>
2021-12-30 10:31:04 +01:00
Felix Fontein
113cbb6eb8 Prepare for distutils.version being removed in Python 3.12 (#353) (#354)
* Prepare for distutils.version being removed in Python 2.12.

* Fix copy'n'paste error.

* Re-add Loose prefix.

* Fix Python version typo.

* Improve formulation.

* Move message into own line.

* Fix casing, now that the object is no longer called Version.

(cherry picked from commit a539cd6939)
2021-12-24 12:15:45 +01:00
Felix Fontein
3ebed060b7 Next expected release is 1.9.9. 2021-12-13 21:11:58 +01:00
Felix Fontein
270ef0db47 Release 1.9.8. 2021-12-13 20:20:11 +01:00
patchback[bot]
0b306b436a Fix module reference in example (#351) (#352)
openssl_privatekey -> openssl_publickey

(cherry picked from commit 45b7aa797e)

Co-authored-by: Jasmine Hegman <jasmine@jhegman.com>
2021-12-13 06:03:13 +00:00
Felix Fontein
c5519bc557 Prepare 1.9.8 release. 2021-12-13 07:01:04 +01:00
patchback[bot]
23d6f2ae75 Fix CSR copy/paste error (#349) (#350)
The first case about ca_csr has been copy/pasted.
But in the following cases, the CSR must be the certificate csr.

(cherry picked from commit 32dab841d7)

Co-authored-by: Bruno Vernay <brunovern.a@gmail.com>
2021-12-09 21:09:52 +01:00
Felix Fontein
9da7c54ae9 Next release will be 1.9.8. 2021-11-22 12:18:34 +01:00
Felix Fontein
928cb3aa9b Release 1.9.7. 2021-11-22 11:41:02 +01:00
patchback[bot]
3e6815d73f [PR #331/3f40795a backport][stable-1] Extension parsing: add new fallback code which uses the new cryptography API (#345)
* Extension parsing: add new fallback code which uses the new cryptography API (#331)

* Add new code as fallback which re-serializes de-serialized extensions using the new cryptography API.

* Forgot Base64 encoding.

* Add extension by OID tests.

* There's one value which is different with the new code.

* Differences in CI.

* Working around older Jinjas.

* Value depends on which SAN was included.

* Force complete CI run now since cryptography 36.0.0 is out.

ci_complete

(cherry picked from commit 3f40795a98)

* Adjust tests.

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-22 08:54:08 +01:00
patchback[bot]
cb08f56066 Use new PKCS#12 deserialization code from cryptography 36.0.0 if available (#302) (#344)
* Use new PKCS#12 deserialization code from cryptography 36.0.0 if available.

* Refactor into smaller functions.

* Force complete CI run now since cryptography 36.0.0 is out.

ci_complete

(cherry picked from commit 73bc0f5de7)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-22 08:27:33 +01:00
Felix Fontein
e3f486a063 Prepare 1.9.7 releaese. 2021-11-22 07:41:21 +01:00
patchback[bot]
0a1e25e16a Fix collection dependency installation in CI. (#341) (#342)
(cherry picked from commit f1a6baadc7)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-18 21:21:57 +01:00
patchback[bot]
ff4966ad3f Fix compatibility to fetch_url change in ansible-core devel (#339) (#340)
* Fix compatibility to fetch_url change in ansible-core devel.

* Adjust tests.

(cherry picked from commit 5de50b9f91)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-17 21:46:13 +01:00
patchback[bot]
0cb10be2d5 Replace RHEL 8.4 by RHEL 8.5 for devel. (#337) (#338)
(cherry picked from commit cf0d2679aa)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-17 07:07:31 +00:00
patchback[bot]
901863989b This is no longer a problem with the dev version of cryptography. (#335) (#336)
(cherry picked from commit 2d388bf8d0)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-13 23:31:52 +01:00
Felix Fontein
99377764c1 Replace Bash codecov uploader by new Python codecov uploader. (#333) (#334)
ci_coverage

(cherry picked from commit 056a86fcae)
2021-11-13 13:22:01 +01:00
patchback[bot]
426d70fbcf luks_device: add built-in signature wiper to work around older wipefs versions with LUKS2 containers (#327) (#330)
* Use 'cryptsetup erase' to kill LUKS signature.

* Adjust unit test.

* Use own wiper for LUKS headers.

* Add comments.

* Fix tests.

* Update changelog.

* Remove 'cryptsetup erase'.

* Improve error messages.

(cherry picked from commit ebbfd7c56f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-11 07:17:45 +01:00
patchback[bot]
f315722b31 Replace Fedora 33 with Fedora 35 for devel tests. (#328) (#329)
(cherry picked from commit 91d98c4413)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-09 05:52:42 +01:00
patchback[bot]
73afe8e742 acme_certificate: fix crash when using fullchain_dest (#324) (#325)
* Fix crash when using fullchain_dest.

* Adjust changelog.

* Update plugins/module_utils/acme/backend_cryptography.py

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
(cherry picked from commit 51b6bb210d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-11-05 09:35:10 +01:00
Felix Fontein
db67b8a857 Next expected release is 1.9.7. 2021-10-30 18:21:40 +02:00
Felix Fontein
e05475d58a Release 1.9.6. 2021-10-30 17:48:48 +02:00
Felix Fontein
dceee8f50e Prepare 1.9.6 release. 2021-10-30 17:07:49 +02:00
Felix Fontein
b893252ad1 [stable-1] cryptography support: improve Python 2 Unicode handling (#314)
* Improve Python 2 Unicode handling. (#313)

(cherry picked from commit eb8dabce84)

* Remove test since it doesn't work with pyOpenSSL.

* Completely remove test.

* Update plugins/module_utils/crypto/cryptography_support.py
2021-10-29 21:10:57 +02:00
patchback[bot]
0755a2b657 Remove centos8 for devel from CI. (#307) (#308)
(cherry picked from commit 78b27ffedb)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-16 09:27:45 +02:00
Felix Fontein
90bf8b0b2e Adjust to latest devel changes.
(cherry picked from commit e735bdab60)
2021-10-12 19:32:56 +02:00
patchback[bot]
5ff28c751d Fix shellcheck error. (#303) (#304)
(cherry picked from commit c68bfedbaa)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-08 15:10:41 +02:00
Felix Fontein
7b08edb5a4 Next expected release is 1.9.6. 2021-10-06 13:35:44 +02:00
Felix Fontein
fbadcbeb29 Release 1.9.5. 2021-10-06 13:08:43 +02:00
Felix Fontein
e991375f55 Prepare 1.9.5 release. 2021-10-05 22:28:03 +02:00
Felix Fontein
33c99014ae [stable-1] Fix PyOpenSSL backends with cryptography 35.0.0 (#300)
* Try to make compatible with cryptography 35.0.0.

* Forgot import.

ci_complete

* Add changelog fragment.
2021-10-05 22:19:11 +02:00
patchback[bot]
fbd6ff6ead x509_certificate: document that *notBefore/*notAfter are not used for idempotency (#298) (#301)
* Document that *notBefore/*notAfter are not used for idempotency.

* Change formulation.

(cherry picked from commit ed03841fd1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 22:20:34 +02:00
patchback[bot]
c4ab2eb3b5 Fix PKCS#12 friendly name extraction for cryptography 35.0.0. (#296) (#299)
(cherry picked from commit d6c0d53442)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 21:37:37 +02:00
patchback[bot]
44b6df0ce5 Support cryptography 35.0.0 for all modules except openssl_pkcs12 (#294) (#297)
* Add some workarounds for cryptography 35.0.0.

* Make fix work with very old cryptography versions as well (which supported multiple backends).

* [TEMP] Disable openssl_pkcs12 tests to see whether everything else works.

* Revert "[TEMP] Disable openssl_pkcs12 tests to see whether everything else works."

This reverts commit 3f905bc795.

* Add changelog fragment.

* Remove unnecessary assignment.

* Simplify code change.

* [TEMP] Disable openssl_pkcs12 tests to see whether everything else works.

* Revert "[TEMP] Disable openssl_pkcs12 tests to see whether everything else works."

This reverts commit fdb210528e.

(cherry picked from commit a2a7d94055)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 17:23:35 +02:00
Felix Fontein
14a42505a9 Ansible-core devel dropped support for Python 2.6.
(cherry picked from commit 2a7e452cf8)
2021-10-01 13:46:08 +02:00
Felix Fontein
44cbd33cb7 Run CI on stable branches only once per week.
(cherry picked from commit 24e7d07973)
2021-10-01 13:44:44 +02:00
Felix Fontein
4411a71d06 Temporarily fix CI for cryptography 35.0.0 release. (#292)
(cherry picked from commit 57c364fe87)
2021-09-30 13:45:38 +02:00
Felix Fontein
bfe37bc668 Next expected 1.x.y release is 1.9.5. 2021-09-28 17:31:41 +02:00
125 changed files with 3976 additions and 686 deletions

View File

@@ -19,6 +19,11 @@ schedules:
branches: branches:
include: include:
- main - main
- cron: 0 12 * * 0
displayName: Weekly (old stable branches)
always: true
branches:
include:
- stable-* - stable-*
variables: variables:
@@ -36,88 +41,40 @@ variables:
resources: resources:
containers: containers:
- container: default - container: default
image: quay.io/ansible/azure-pipelines-test-container:1.9.0 image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard pool: Standard
stages: stages:
### Sanity & units ### Sanity & units
- stage: Ansible_devel - stage: Ansible_2_13
displayName: Sanity & Units devel displayName: Sanity & Units 2.13
dependsOn: [] dependsOn: []
jobs: jobs:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
targets: targets:
- name: Sanity - name: Sanity
test: 'devel/sanity/1' test: '2.13/sanity/1'
- name: Sanity Extra # Only on devel - name: Sanity Extra # Only on devel
test: 'devel/sanity/extra' test: '2.13/sanity/extra'
- name: Units - name: Units
test: 'devel/units/1' test: '2.13/units/1'
- stage: Ansible_2_12
displayName: Sanity & Units 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
test: '2.12/sanity/1'
- name: Units
test: '2.12/units/1'
- stage: Ansible_2_11
displayName: Sanity & Units 2.11
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
test: '2.11/sanity/1'
- name: Units
test: '2.11/units/1'
- stage: Ansible_2_10
displayName: Sanity & Units 2.10
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
test: '2.10/sanity/1'
- name: Units
test: '2.10/units/1'
- stage: Ansible_2_9
displayName: Sanity & Units 2.9
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
test: '2.9/sanity/1'
- name: Units
test: '2.9/units/1'
### Docker ### Docker
- stage: Docker_devel - stage: Docker_2_13
displayName: Docker devel displayName: Docker 2.13
dependsOn: [] dependsOn: []
jobs: jobs:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
testFormat: devel/linux/{0}/1 testFormat: 2.13/linux/{0}/1
targets: targets:
- name: CentOS 6
test: centos6
- name: CentOS 7 - name: CentOS 7
test: centos7 test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 33
test: fedora33
- name: Fedora 34 - name: Fedora 34
test: fedora34 test: fedora34
- name: Fedora 35
test: fedora35
- name: openSUSE 15 py2 - name: openSUSE 15 py2
test: opensuse15py2 test: opensuse15py2
- name: openSUSE 15 py3 - name: openSUSE 15 py3
@@ -126,227 +83,52 @@ stages:
test: ubuntu1804 test: ubuntu1804
- name: Ubuntu 20.04 - name: Ubuntu 20.04
test: ubuntu2004 test: ubuntu2004
- stage: Docker_2_12
displayName: Docker 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/linux/{0}/1
targets:
- name: CentOS 8
test: centos8
- name: Fedora 33
test: fedora33
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 20.04
test: ubuntu2004
- stage: Docker_2_11
displayName: Docker 2.11
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.11/linux/{0}/1
targets:
- name: CentOS 7
test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 32
test: fedora32
- name: openSUSE 15 py2
test: opensuse15py2
- name: Ubuntu 18.04
test: ubuntu1804
- stage: Docker_2_10
displayName: Docker 2.10
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.10/linux/{0}/1
targets:
- name: CentOS 6
test: centos6
- name: Fedora 31
test: fedora31
- name: Ubuntu 16.04
test: ubuntu1604
- stage: Docker_2_9
displayName: Docker 2.9
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.9/linux/{0}/1
targets:
- name: CentOS 6
test: centos6
- name: CentOS 7
test: centos7
- name: Fedora 31
test: fedora31
- name: Ubuntu 16.04
test: ubuntu1604
- name: Ubuntu 18.04
test: ubuntu1804
### Remote ### Remote
- stage: Remote_devel - stage: Remote_2_13
displayName: Remote devel displayName: Remote 2.13
dependsOn: [] dependsOn: []
jobs: jobs:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
testFormat: devel/{0}/1 testFormat: 2.13/{0}/1
targets: targets:
- name: macOS 11.1 # - name: macOS 12.0
test: macos/11.1 # test: macos/12.0
- name: RHEL 7.9 - name: RHEL 7.9
test: rhel/7.9 test: rhel/7.9
- name: RHEL 8.4 - name: RHEL 8.5
test: rhel/8.4 test: rhel/8.5
- name: FreeBSD 12.2 # - name: FreeBSD 12.4
test: freebsd/12.2 # test: freebsd/12.4
- name: FreeBSD 13.0 # - name: FreeBSD 13.1
test: freebsd/13.0 # test: freebsd/13.1
- stage: Remote_2_12
displayName: Remote 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/{0}/1
targets:
- name: macOS 11.1
test: macos/11.1
- name: RHEL 8.4
test: rhel/8.4
- name: FreeBSD 13.0
test: freebsd/13.0
- stage: Remote_2_11
displayName: Remote 2.11
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.11/{0}/1
targets:
- name: RHEL 7.9
test: rhel/7.9
- name: RHEL 8.3
test: rhel/8.3
- name: FreeBSD 12.2
test: freebsd/12.2
- stage: Remote_2_10
displayName: Remote 2.10
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.10/{0}/1
targets:
- name: OS X 10.11
test: osx/10.11
- name: macOS 10.15
test: macos/10.15
- name: FreeBSD 12.1
test: freebsd/12.1
- stage: Remote_2_9
displayName: Remote 2.9
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.9/{0}/1
targets:
- name: 'RHEL 7.8'
test: 'rhel/7.8'
### cloud ### cloud
- stage: Cloud_devel - stage: Cloud_2_13
displayName: Cloud devel displayName: Cloud 2.13
dependsOn: [] dependsOn: []
jobs: jobs:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
nameFormat: Python {0} nameFormat: Python {0}
testFormat: devel/cloud/{0}/1 testFormat: 2.13/cloud/{0}/1
targets: targets:
- test: 2.6
- test: 2.7 - test: 2.7
- test: 3.5 - test: 3.5
- test: 3.6 - test: 3.6
- test: 3.7 - test: 3.7
- test: 3.8 # - test: 3.8
- test: 3.9 - test: 3.9
- test: "3.10" - test: "3.10"
- stage: Cloud_2_12
displayName: Cloud 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.12/cloud/{0}/1
targets:
- test: 3.9
- stage: Cloud_2_11
displayName: Cloud 2.11
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.11/cloud/{0}/1
targets:
- test: 3.8
- stage: Cloud_2_10
displayName: Cloud 2.10
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.10/cloud/{0}/1
targets:
- test: 3.6
- stage: Cloud_2_9
displayName: Cloud 2.9
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.9/cloud/{0}/1
targets:
- test: 3.5
## Finally ## Finally
- stage: Summary - stage: Summary
condition: succeededOrFailed() condition: succeededOrFailed()
dependsOn: dependsOn:
- Ansible_devel - Ansible_2_13
- Ansible_2_12 - Remote_2_13
- Ansible_2_11 - Docker_2_13
- Ansible_2_10 - Cloud_2_13
- Ansible_2_9
- Remote_devel
- Remote_2_12
- Remote_2_11
- Remote_2_10
- Remote_2_9
- Docker_devel
- Docker_2_12
- Docker_2_11
- Docker_2_10
- Docker_2_9
- Cloud_devel
- Cloud_2_12
- Cloud_2_11
- Cloud_2_10
- Cloud_2_9
jobs: jobs:
- template: templates/coverage.yml - template: templates/coverage.yml

View File

@@ -9,9 +9,13 @@ PATH="${PWD}/bin:${PATH}"
mkdir "${agent_temp_directory}/coverage/" mkdir "${agent_temp_directory}/coverage/"
if [[ "$(ansible --version)" =~ \ 2\.9\. ]]; then
exit
fi
options=(--venv --venv-system-site-packages --color -v) options=(--venv --venv-system-site-packages --color -v)
ansible-test coverage combine --export "${agent_temp_directory}/coverage/" "${options[@]}" ansible-test coverage combine --group-by command --export "${agent_temp_directory}/coverage/" "${options[@]}"
if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then
# Only analyze coverage if the installed version of ansible-test supports it. # Only analyze coverage if the installed version of ansible-test supports it.

View File

@@ -0,0 +1,101 @@
#!/usr/bin/env python
"""
Upload code coverage reports to codecov.io.
Multiple coverage files from multiple languages are accepted and aggregated after upload.
Python coverage, as well as PowerShell and Python stubs can all be uploaded.
"""
import argparse
import dataclasses
import pathlib
import shutil
import subprocess
import tempfile
import typing as t
import urllib.request
@dataclasses.dataclass(frozen=True)
class CoverageFile:
name: str
path: pathlib.Path
flags: t.List[str]
@dataclasses.dataclass(frozen=True)
class Args:
dry_run: bool
path: pathlib.Path
def parse_args() -> Args:
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--dry-run', action='store_true')
parser.add_argument('path', type=pathlib.Path)
args = parser.parse_args()
# Store arguments in a typed dataclass
fields = dataclasses.fields(Args)
kwargs = {field.name: getattr(args, field.name) for field in fields}
return Args(**kwargs)
def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]:
processed = []
for file in directory.joinpath('reports').glob('coverage*.xml'):
name = file.stem.replace('coverage=', '')
# Get flags from name
flags = name.replace('-powershell', '').split('=') # Drop '-powershell' suffix
flags = [flag if not flag.startswith('stub') else flag.split('-')[0] for flag in flags] # Remove "-01" from stub files
processed.append(CoverageFile(name, file, flags))
return tuple(processed)
def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], dry_run: bool = False) -> None:
for file in files:
cmd = [
str(codecov_bin),
'--name', file.name,
'--file', str(file.path),
]
for flag in file.flags:
cmd.extend(['--flags', flag])
if dry_run:
print(f'DRY-RUN: Would run command: {cmd}')
continue
subprocess.run(cmd, check=True)
def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = False) -> None:
if dry_run:
print(f'DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}')
return
with urllib.request.urlopen(url) as resp:
with dest.open('w+b') as f:
# Read data in chunks rather than all at once
shutil.copyfileobj(resp, f, 64 * 1024)
dest.chmod(flags)
def main():
args = parse_args()
url = 'https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov'
with tempfile.TemporaryDirectory(prefix='codecov-') as tmpdir:
codecov_bin = pathlib.Path(tmpdir) / 'codecov'
download_file(url, codecov_bin, 0o755, args.dry_run)
files = process_files(args.path)
upload_files(codecov_bin, files, args.dry_run)
if __name__ == '__main__':
main()

View File

@@ -1,27 +0,0 @@
#!/usr/bin/env bash
# Upload code coverage reports to codecov.io.
# Multiple coverage files from multiple languages are accepted and aggregated after upload.
# Python coverage, as well as PowerShell and Python stubs can all be uploaded.
set -o pipefail -eu
output_path="$1"
curl --silent --show-error https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh > codecov.sh
for file in "${output_path}"/reports/coverage*.xml; do
name="${file}"
name="${name##*/}" # remove path
name="${name##coverage=}" # remove 'coverage=' prefix if present
name="${name%.xml}" # remove '.xml' suffix
bash codecov.sh \
-f "${file}" \
-n "${name}" \
-X coveragepy \
-X gcov \
-X fix \
-X search \
-X xcode \
|| echo "Failed to upload code coverage report to codecov.io: ${file}"
done

View File

@@ -5,6 +5,10 @@ set -o pipefail -eu
PATH="${PWD}/bin:${PATH}" PATH="${PWD}/bin:${PATH}"
if [[ "$(ansible --version)" =~ \ 2\.9\. ]]; then
exit
fi
if ! ansible-test --help >/dev/null 2>&1; then if ! ansible-test --help >/dev/null 2>&1; then
# Install the devel version of ansible-test for generating code coverage reports. # Install the devel version of ansible-test for generating code coverage reports.
# This is only used by Ansible Collections, which are typically tested against multiple Ansible versions (in separate jobs). # This is only used by Ansible Collections, which are typically tested against multiple Ansible versions (in separate jobs).
@@ -12,4 +16,4 @@ if ! ansible-test --help >/dev/null 2>&1; then
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
fi fi
ansible-test coverage xml --stub --venv --venv-system-site-packages --color -v ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v

View File

@@ -33,7 +33,7 @@ jobs:
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml" summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
displayName: Publish to Azure Pipelines displayName: Publish to Azure Pipelines
condition: gt(variables.coverageFileCount, 0) condition: gt(variables.coverageFileCount, 0)
- bash: .azure-pipelines/scripts/publish-codecov.sh "$(outputPath)" - bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
displayName: Publish to codecov.io displayName: Publish to codecov.io
condition: gt(variables.coverageFileCount, 0) condition: gt(variables.coverageFileCount, 0)
continueOnError: true continueOnError: true

218
.github/workflows/ansible-test.yml vendored Normal file
View File

@@ -0,0 +1,218 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
name: EOL CI
on:
# Run EOL CI against all pushes (direct commits, also merged PRs), Pull Requests
push:
branches:
- stable-1
pull_request:
concurrency:
# Make sure there is at most one active run per PR, but do not cancel any non-PR runs
group: ${{ github.workflow }}-${{ (github.head_ref && github.event.number) || github.run_id }}
cancel-in-progress: true
jobs:
sanity:
name: EOL Sanity (Ⓐ${{ matrix.ansible }})
strategy:
matrix:
ansible:
- '2.9'
- '2.10'
- '2.11'
- '2.12'
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
runs-on: >-
${{ contains(fromJson(
'["2.9", "2.10", "2.11"]'
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
steps:
- name: Perform sanity testing
uses: felixfontein/ansible-test-gh-action@main
with:
ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
testing-type: sanity
units:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
runs-on: >-
${{ contains(fromJson(
'["2.9", "2.10", "2.11"]'
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
name: EOL Units (Ⓐ${{ matrix.ansible }})
strategy:
# As soon as the first unit test fails, cancel the others to free up the CI queue
fail-fast: true
matrix:
ansible:
- '2.9'
- '2.10'
- '2.11'
- '2.12'
steps:
- name: >-
Perform unit testing against
Ansible version ${{ matrix.ansible }}
uses: felixfontein/ansible-test-gh-action@main
with:
ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
testing-type: units
integration:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
runs-on: >-
${{ contains(fromJson(
'["2.9", "2.10", "2.11"]'
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
name: EOL I (Ⓐ${{ matrix.ansible }}+${{ matrix.docker }}+py${{ matrix.python }}:${{ matrix.target }})
strategy:
fail-fast: false
matrix:
ansible:
- ''
docker:
- ''
python:
- ''
target:
- ''
exclude:
- ansible: ''
include:
# 2.9
- ansible: '2.9'
docker: centos6
python: ''
target: shippable/posix/group1/
#- ansible: '2.9'
# docker: centos7
# python: ''
# target: shippable/posix/group1/
- ansible: '2.9'
docker: fedora31
python: ''
target: shippable/posix/group1/
- ansible: '2.9'
docker: ubuntu1604
python: ''
target: shippable/posix/group1/
- ansible: '2.9'
docker: ubuntu1804
python: ''
target: shippable/posix/group1/
- ansible: '2.9'
docker: default
python: '2.7'
target: shippable/cloud/group1/
# 2.10
- ansible: '2.10'
docker: centos6
python: ''
target: shippable/posix/group1/
- ansible: '2.10'
docker: fedora31
python: ''
target: shippable/posix/group1/
- ansible: '2.10'
docker: ubuntu1604
python: ''
target: shippable/posix/group1/
- ansible: '2.10'
docker: default
python: '3.6'
target: shippable/cloud/group1/
# 2.11
#- ansible: '2.11'
# docker: centos7
# python: ''
# target: shippable/posix/group1/
- ansible: '2.11'
docker: fedora32
python: ''
target: shippable/posix/group1/
- ansible: '2.11'
docker: opensuse15py2
python: ''
target: shippable/posix/group1/
- ansible: '2.11'
docker: ubuntu1804
python: ''
target: shippable/posix/group1/
- ansible: '2.11'
docker: default
python: '3.8'
target: shippable/cloud/group1/
# 2.12
- ansible: '2.12'
docker: centos6
python: ''
target: shippable/posix/group1/
- ansible: '2.12'
docker: fedora33
python: ''
target: shippable/posix/group1/
- ansible: '2.12'
docker: opensuse15
python: ''
target: shippable/posix/group1/
- ansible: '2.12'
docker: ubuntu2004
python: ''
target: shippable/posix/group1/
- ansible: '2.12'
docker: default
python: '2.6'
target: shippable/cloud/group1/
- ansible: '2.12'
docker: default
python: '3.9'
target: shippable/cloud/group1/
steps:
- name: >-
Perform integration testing against
Ansible version ${{ matrix.ansible }}
under Python ${{ matrix.python }}
uses: felixfontein/ansible-test-gh-action@main
with:
ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
docker-image: ${{ matrix.docker }}
integration-continue-on-error: 'false'
integration-diff: 'false'
integration-retry-on-error: 'true'
pre-test-cmd: >-
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
;
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git ../../community/general
pull-request-change-detection: 'true'
target: ${{ matrix.target }}
target-python-version: ${{ matrix.python }}
testing-type: integration

20
.github/workflows/import-galaxy.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
name: import-galaxy
'on':
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
push:
branches:
- main
- stable-*
pull_request:
jobs:
import-galaxy:
permissions:
contents: read
name: Test to import built collection artifact with Galaxy importer
uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main

202
Apache-2.0.txt Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://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
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

866
CHANGELOG.md Normal file
View File

@@ -0,0 +1,866 @@
# Community Crypto Release Notes
**Topics**
- <a href="#v1-9-25">v1\.9\.25</a>
- <a href="#release-summary">Release Summary</a>
- <a href="#bugfixes">Bugfixes</a>
- <a href="#v1-9-24">v1\.9\.24</a>
- <a href="#release-summary-1">Release Summary</a>
- <a href="#bugfixes-1">Bugfixes</a>
- <a href="#v1-9-23">v1\.9\.23</a>
- <a href="#release-summary-2">Release Summary</a>
- <a href="#bugfixes-2">Bugfixes</a>
- <a href="#v1-9-22">v1\.9\.22</a>
- <a href="#release-summary-3">Release Summary</a>
- <a href="#bugfixes-3">Bugfixes</a>
- <a href="#v1-9-21">v1\.9\.21</a>
- <a href="#release-summary-4">Release Summary</a>
- <a href="#bugfixes-4">Bugfixes</a>
- <a href="#v1-9-20">v1\.9\.20</a>
- <a href="#release-summary-5">Release Summary</a>
- <a href="#bugfixes-5">Bugfixes</a>
- <a href="#v1-9-19">v1\.9\.19</a>
- <a href="#release-summary-6">Release Summary</a>
- <a href="#bugfixes-6">Bugfixes</a>
- <a href="#v1-9-18">v1\.9\.18</a>
- <a href="#release-summary-7">Release Summary</a>
- <a href="#bugfixes-7">Bugfixes</a>
- <a href="#v1-9-17">v1\.9\.17</a>
- <a href="#release-summary-8">Release Summary</a>
- <a href="#bugfixes-8">Bugfixes</a>
- <a href="#v1-9-16">v1\.9\.16</a>
- <a href="#release-summary-9">Release Summary</a>
- <a href="#bugfixes-9">Bugfixes</a>
- <a href="#v1-9-15">v1\.9\.15</a>
- <a href="#release-summary-10">Release Summary</a>
- <a href="#bugfixes-10">Bugfixes</a>
- <a href="#v1-9-14">v1\.9\.14</a>
- <a href="#release-summary-11">Release Summary</a>
- <a href="#bugfixes-11">Bugfixes</a>
- <a href="#v1-9-13">v1\.9\.13</a>
- <a href="#release-summary-12">Release Summary</a>
- <a href="#bugfixes-12">Bugfixes</a>
- <a href="#v1-9-12">v1\.9\.12</a>
- <a href="#release-summary-13">Release Summary</a>
- <a href="#bugfixes-13">Bugfixes</a>
- <a href="#known-issues">Known Issues</a>
- <a href="#v1-9-11">v1\.9\.11</a>
- <a href="#release-summary-14">Release Summary</a>
- <a href="#bugfixes-14">Bugfixes</a>
- <a href="#v1-9-10">v1\.9\.10</a>
- <a href="#release-summary-15">Release Summary</a>
- <a href="#bugfixes-15">Bugfixes</a>
- <a href="#v1-9-9">v1\.9\.9</a>
- <a href="#bugfixes-16">Bugfixes</a>
- <a href="#v1-9-8">v1\.9\.8</a>
- <a href="#release-summary-16">Release Summary</a>
- <a href="#v1-9-7">v1\.9\.7</a>
- <a href="#release-summary-17">Release Summary</a>
- <a href="#minor-changes">Minor Changes</a>
- <a href="#bugfixes-17">Bugfixes</a>
- <a href="#v1-9-6">v1\.9\.6</a>
- <a href="#release-summary-18">Release Summary</a>
- <a href="#bugfixes-18">Bugfixes</a>
- <a href="#v1-9-5">v1\.9\.5</a>
- <a href="#release-summary-19">Release Summary</a>
- <a href="#bugfixes-19">Bugfixes</a>
- <a href="#v1-9-4">v1\.9\.4</a>
- <a href="#release-summary-20">Release Summary</a>
- <a href="#bugfixes-20">Bugfixes</a>
- <a href="#v1-9-3">v1\.9\.3</a>
- <a href="#release-summary-21">Release Summary</a>
- <a href="#bugfixes-21">Bugfixes</a>
- <a href="#v1-9-2">v1\.9\.2</a>
- <a href="#release-summary-22">Release Summary</a>
- <a href="#v1-9-1">v1\.9\.1</a>
- <a href="#release-summary-23">Release Summary</a>
- <a href="#v1-9-0">v1\.9\.0</a>
- <a href="#release-summary-24">Release Summary</a>
- <a href="#minor-changes-1">Minor Changes</a>
- <a href="#bugfixes-22">Bugfixes</a>
- <a href="#v1-8-0">v1\.8\.0</a>
- <a href="#release-summary-25">Release Summary</a>
- <a href="#minor-changes-2">Minor Changes</a>
- <a href="#bugfixes-23">Bugfixes</a>
- <a href="#v1-7-1">v1\.7\.1</a>
- <a href="#release-summary-26">Release Summary</a>
- <a href="#bugfixes-24">Bugfixes</a>
- <a href="#v1-7-0">v1\.7\.0</a>
- <a href="#release-summary-27">Release Summary</a>
- <a href="#minor-changes-3">Minor Changes</a>
- <a href="#bugfixes-25">Bugfixes</a>
- <a href="#new-modules">New Modules</a>
- <a href="#v1-6-2">v1\.6\.2</a>
- <a href="#release-summary-28">Release Summary</a>
- <a href="#bugfixes-26">Bugfixes</a>
- <a href="#v1-6-1">v1\.6\.1</a>
- <a href="#release-summary-29">Release Summary</a>
- <a href="#bugfixes-27">Bugfixes</a>
- <a href="#v1-6-0">v1\.6\.0</a>
- <a href="#release-summary-30">Release Summary</a>
- <a href="#minor-changes-4">Minor Changes</a>
- <a href="#deprecated-features">Deprecated Features</a>
- <a href="#bugfixes-28">Bugfixes</a>
- <a href="#v1-5-0">v1\.5\.0</a>
- <a href="#release-summary-31">Release Summary</a>
- <a href="#minor-changes-5">Minor Changes</a>
- <a href="#deprecated-features-1">Deprecated Features</a>
- <a href="#bugfixes-29">Bugfixes</a>
- <a href="#v1-4-0">v1\.4\.0</a>
- <a href="#release-summary-32">Release Summary</a>
- <a href="#minor-changes-6">Minor Changes</a>
- <a href="#bugfixes-30">Bugfixes</a>
- <a href="#v1-3-0">v1\.3\.0</a>
- <a href="#release-summary-33">Release Summary</a>
- <a href="#minor-changes-7">Minor Changes</a>
- <a href="#bugfixes-31">Bugfixes</a>
- <a href="#new-modules-1">New Modules</a>
- <a href="#v1-2-0">v1\.2\.0</a>
- <a href="#release-summary-34">Release Summary</a>
- <a href="#minor-changes-8">Minor Changes</a>
- <a href="#security-fixes">Security Fixes</a>
- <a href="#bugfixes-32">Bugfixes</a>
- <a href="#v1-1-1">v1\.1\.1</a>
- <a href="#release-summary-35">Release Summary</a>
- <a href="#bugfixes-33">Bugfixes</a>
- <a href="#v1-1-0">v1\.1\.0</a>
- <a href="#release-summary-36">Release Summary</a>
- <a href="#minor-changes-9">Minor Changes</a>
- <a href="#bugfixes-34">Bugfixes</a>
- <a href="#new-modules-2">New Modules</a>
- <a href="#v1-0-0">v1\.0\.0</a>
- <a href="#release-summary-37">Release Summary</a>
- <a href="#minor-changes-10">Minor Changes</a>
- <a href="#deprecated-features-2">Deprecated Features</a>
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
- <a href="#bugfixes-35">Bugfixes</a>
- <a href="#new-modules-3">New Modules</a>
<a id="v1-9-25"></a>
## v1\.9\.25
<a id="release-summary"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes"></a>
### Bugfixes
* crypto\.math module utils \- change return values for <code>quick\_is\_not\_prime\(\)</code> for special cases that do not appear when using the collection \([https\://github\.com/ansible\-collections/community\.crypto/pull/733](https\://github\.com/ansible\-collections/community\.crypto/pull/733)\)\.
* ecs\_certificate \- fixed <code>csr</code> option to be empty and allow renewal of a specific certificate according to the Renewal Information specification \([https\://github\.com/ansible\-collections/community\.crypto/pull/740](https\://github\.com/ansible\-collections/community\.crypto/pull/740)\)\.
<a id="v1-9-24"></a>
## v1\.9\.24
<a id="release-summary-1"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-1"></a>
### Bugfixes
* openssl\_dhparam \- was using an internal function instead of the public API to load DH param files when using the <code>cryptography</code> backend\. The internal function was removed in cryptography 42\.0\.0\. The module now uses the public API\, which has been available since support for DH params was added to cryptography \([https\://github\.com/ansible\-collections/community\.crypto/pull/698](https\://github\.com/ansible\-collections/community\.crypto/pull/698)\)\.
* openssl\_privatekey\_info \- <code>check\_consistency\=true</code> no longer works for RSA keys with cryptography 42\.0\.0\+ \([https\://github\.com/ansible\-collections/community\.crypto/pull/701](https\://github\.com/ansible\-collections/community\.crypto/pull/701)\)\.
* x509\_certificate \- when using the PyOpenSSL backend with <code>provider\=assertonly</code>\, better handle unexpected errors when validating private keys \([https\://github\.com/ansible\-collections/community\.crypto/pull/704](https\://github\.com/ansible\-collections/community\.crypto/pull/704)\)\.
<a id="v1-9-23"></a>
## v1\.9\.23
<a id="release-summary-2"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-2"></a>
### Bugfixes
* openssl\_pkcs12 \- modify autodetect to not detect pyOpenSSL \>\= 23\.3\.0\, which removed PKCS\#12 support \([https\://github\.com/ansible\-collections/community\.crypto/pull/666](https\://github\.com/ansible\-collections/community\.crypto/pull/666)\)\.
<a id="v1-9-22"></a>
## v1\.9\.22
<a id="release-summary-3"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-3"></a>
### Bugfixes
* openssh\_keypair \- always generate a new key pair if the private key does not exist\. Previously\, the module would fail when <code>regenerate\=fail</code> without an existing key\, contradicting the documentation \([https\://github\.com/ansible\-collections/community\.crypto/pull/598](https\://github\.com/ansible\-collections/community\.crypto/pull/598)\)\.
<a id="v1-9-21"></a>
## v1\.9\.21
<a id="release-summary-4"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-4"></a>
### Bugfixes
* action plugin helper \- fix handling of deprecations for ansible\-core 2\.14\.2 \([https\://github\.com/ansible\-collections/community\.crypto/pull/572](https\://github\.com/ansible\-collections/community\.crypto/pull/572)\)\.
* openssl\_csr\, openssl\_csr\_pipe \- prevent invalid values for <code>crl\_distribution\_points</code> that do not have one of <code>full\_name</code>\, <code>relative\_name</code>\, and <code>crl\_issuer</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/560](https\://github\.com/ansible\-collections/community\.crypto/pull/560)\)\.
<a id="v1-9-20"></a>
## v1\.9\.20
<a id="release-summary-5"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-5"></a>
### Bugfixes
* openssl\_publickey\_info \- do not crash with internal error when public key cannot be parsed \([https\://github\.com/ansible\-collections/community\.crypto/pull/551](https\://github\.com/ansible\-collections/community\.crypto/pull/551)\)\.
<a id="v1-9-19"></a>
## v1\.9\.19
<a id="release-summary-6"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-6"></a>
### Bugfixes
* openssl\_privatekey\_pipe \- ensure compatibility with newer versions of ansible\-core \([https\://github\.com/ansible\-collections/community\.crypto/pull/515](https\://github\.com/ansible\-collections/community\.crypto/pull/515)\)\.
<a id="v1-9-18"></a>
## v1\.9\.18
<a id="release-summary-7"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-7"></a>
### Bugfixes
* openssl\_pkcs12 \- when using the pyOpenSSL backend\, do not crash when trying to read non\-existing other certificates \([https\://github\.com/ansible\-collections/community\.crypto/issues/486](https\://github\.com/ansible\-collections/community\.crypto/issues/486)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/487](https\://github\.com/ansible\-collections/community\.crypto/pull/487)\)\.
<a id="v1-9-17"></a>
## v1\.9\.17
<a id="release-summary-8"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-8"></a>
### Bugfixes
* Include <code>Apache\-2\.0\.txt</code> file for <code>plugins/module\_utils/crypto/\_obj2txt\.py</code> and <code>plugins/module\_utils/crypto/\_objects\_data\.py</code>\.
* openssl\_csr \- the module no longer crashes with \'permitted\_subtrees/excluded\_subtrees must be a non\-empty list or None\' if only one of <code>name\_constraints\_permitted</code> and <code>name\_constraints\_excluded</code> is provided \([https\://github\.com/ansible\-collections/community\.crypto/issues/481](https\://github\.com/ansible\-collections/community\.crypto/issues/481)\)\.
* x509\_crl \- do not crash when signing CRL with Ed25519 or Ed448 keys \([https\://github\.com/ansible\-collections/community\.crypto/issues/473](https\://github\.com/ansible\-collections/community\.crypto/issues/473)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/474](https\://github\.com/ansible\-collections/community\.crypto/pull/474)\)\.
<a id="v1-9-16"></a>
## v1\.9\.16
<a id="release-summary-9"></a>
### Release Summary
Maintenance and bugfix release\.
<a id="bugfixes-9"></a>
### Bugfixes
* Include <code>simplified\_bsd\.txt</code> license file for the ECS module utils\.
* certificate\_complete\_chain \- do not stop execution if an unsupported signature algorithm is encountered\; warn instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/457](https\://github\.com/ansible\-collections/community\.crypto/pull/457)\)\.
<a id="v1-9-15"></a>
## v1\.9\.15
<a id="release-summary-10"></a>
### Release Summary
Maintenance release\.
<a id="bugfixes-10"></a>
### Bugfixes
* Include <code>PSF\-license\.txt</code> file for <code>plugins/module\_utils/\_version\.py</code>\.
<a id="v1-9-14"></a>
## v1\.9\.14
<a id="release-summary-11"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-11"></a>
### Bugfixes
* Make collection more robust when PyOpenSSL is used with an incompatible cryptography version \([https\://github\.com/ansible\-collections/community\.crypto/pull/446](https\://github\.com/ansible\-collections/community\.crypto/pull/446)\)\.
* openssh\_\* modules \- fix exception handling to report traceback to users for enhanced traceability \([https\://github\.com/ansible\-collections/community\.crypto/pull/417](https\://github\.com/ansible\-collections/community\.crypto/pull/417)\)\.
* x509\_crl \- fix crash when <code>issuer</code> for a revoked certificate is specified \([https\://github\.com/ansible\-collections/community\.crypto/pull/441](https\://github\.com/ansible\-collections/community\.crypto/pull/441)\)\.
<a id="v1-9-13"></a>
## v1\.9\.13
<a id="release-summary-12"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-12"></a>
### Bugfixes
* luks\_device \- fix parsing of <code>lsblk</code> output when device name ends with <code>crypt</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/409](https\://github\.com/ansible\-collections/community\.crypto/issues/409)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/410](https\://github\.com/ansible\-collections/community\.crypto/pull/410)\)\.
<a id="v1-9-12"></a>
## v1\.9\.12
<a id="release-summary-13"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-13"></a>
### Bugfixes
* certificate\_complete\_chain \- allow multiple potential intermediate certificates to have the same subject \([https\://github\.com/ansible\-collections/community\.crypto/issues/399](https\://github\.com/ansible\-collections/community\.crypto/issues/399)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/403](https\://github\.com/ansible\-collections/community\.crypto/pull/403)\)\.
* x509\_certificate \- for the <code>ownca</code> provider\, check whether the CA private key actually belongs to the CA certificate\. This fix only covers the <code>cryptography</code> backend\, not the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
* x509\_certificate \- regenerate certificate when the CA\'s public key changes for <code>provider\=ownca</code>\. This fix only covers the <code>cryptography</code> backend\, not the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
* x509\_certificate \- regenerate certificate when the CA\'s subject changes for <code>provider\=ownca</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/400](https\://github\.com/ansible\-collections/community\.crypto/issues/400)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/402](https\://github\.com/ansible\-collections/community\.crypto/pull/402)\)\.
* x509\_certificate \- regenerate certificate when the private key changes for <code>provider\=selfsigned</code>\. This fix only covers the <code>cryptography</code> backend\, not the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
<a id="known-issues"></a>
### Known Issues
* x509\_certificate \- when using the <code>ownca</code> provider with the <code>pyopenssl</code> backend\, changing the CA\'s public key does not cause regeneration of the certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
* x509\_certificate \- when using the <code>ownca</code> provider with the <code>pyopenssl</code> backend\, it is possible to specify a CA private key which is not related to the CA certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
* x509\_certificate \- when using the <code>selfsigned</code> provider with the <code>pyopenssl</code> backend\, changing the private key does not cause regeneration of the certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
<a id="v1-9-11"></a>
## v1\.9\.11
<a id="release-summary-14"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-14"></a>
### Bugfixes
* openssh\_cert \- fixed false <code>changed</code> status for <code>host</code> certificates when using <code>full\_idempotence</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/395](https\://github\.com/ansible\-collections/community\.crypto/issues/395)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/396](https\://github\.com/ansible\-collections/community\.crypto/pull/396)\)\.
<a id="v1-9-10"></a>
## v1\.9\.10
<a id="release-summary-15"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-15"></a>
### Bugfixes
* luks\_devices \- set <code>LANG</code> and similar environment variables to avoid translated output\, which can break some of the module\'s functionality like key management \([https\://github\.com/ansible\-collections/community\.crypto/pull/388](https\://github\.com/ansible\-collections/community\.crypto/pull/388)\, [https\://github\.com/ansible\-collections/community\.crypto/issues/385](https\://github\.com/ansible\-collections/community\.crypto/issues/385)\)\.
<a id="v1-9-9"></a>
## v1\.9\.9
<a id="bugfixes-16"></a>
### Bugfixes
* Various modules and plugins \- use vendored version of <code>distutils\.version</code> instead of the deprecated Python standard library <code>distutils</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/353](https\://github\.com/ansible\-collections/community\.crypto/pull/353)\)\.
* certificate\_complete\_chain \- do not append root twice if the chain already ends with a root certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/360](https\://github\.com/ansible\-collections/community\.crypto/pull/360)\)\.
* certificate\_complete\_chain \- do not hang when infinite loop is found \([https\://github\.com/ansible\-collections/community\.crypto/issues/355](https\://github\.com/ansible\-collections/community\.crypto/issues/355)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/360](https\://github\.com/ansible\-collections/community\.crypto/pull/360)\)\.
<a id="v1-9-8"></a>
## v1\.9\.8
<a id="release-summary-16"></a>
### Release Summary
Documentation fix release\. No actual code changes\.
<a id="v1-9-7"></a>
## v1\.9\.7
<a id="release-summary-17"></a>
### Release Summary
Bugfix release with extra forward compatibility for newer versions of cryptography\.
<a id="minor-changes"></a>
### Minor Changes
* acme\_\* modules \- fix usage of <code>fetch\_url</code> with changes in latest ansible\-core <code>devel</code> branch \([https\://github\.com/ansible\-collections/community\.crypto/pull/339](https\://github\.com/ansible\-collections/community\.crypto/pull/339)\)\.
<a id="bugfixes-17"></a>
### Bugfixes
* acme\_certificate \- avoid passing multiple certificates to <code>cryptography</code>\'s X\.509 certificate loader when <code>fullchain\_dest</code> is used \([https\://github\.com/ansible\-collections/community\.crypto/pull/324](https\://github\.com/ansible\-collections/community\.crypto/pull/324)\)\.
* get\_certificate\, openssl\_csr\_info\, x509\_certificate\_info \- add fallback code for extension parsing that works with cryptography 36\.0\.0 and newer\. This code re\-serializes de\-serialized extensions and thus can return slightly different values if the extension in the original CSR resp\. certificate was not canonicalized correctly\. This code is currently used as a fallback if the existing code stops working\, but we will switch it to be the main code in a future release \([https\://github\.com/ansible\-collections/community\.crypto/pull/331](https\://github\.com/ansible\-collections/community\.crypto/pull/331)\)\.
* luks\_device \- now also runs a built\-in LUKS signature cleaner on <code>state\=absent</code> to make sure that also the secondary LUKS2 header is wiped when older versions of wipefs are used \([https\://github\.com/ansible\-collections/community\.crypto/issues/326](https\://github\.com/ansible\-collections/community\.crypto/issues/326)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/327](https\://github\.com/ansible\-collections/community\.crypto/pull/327)\)\.
* openssl\_pkcs12 \- use new PKCS\#12 deserialization infrastructure from cryptography 36\.0\.0 if available \([https\://github\.com/ansible\-collections/community\.crypto/pull/302](https\://github\.com/ansible\-collections/community\.crypto/pull/302)\)\.
<a id="v1-9-6"></a>
## v1\.9\.6
<a id="release-summary-18"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-18"></a>
### Bugfixes
* cryptography backend \- improve Unicode handling for Python 2 \([https\://github\.com/ansible\-collections/community\.crypto/pull/313](https\://github\.com/ansible\-collections/community\.crypto/pull/313)\)\.
<a id="v1-9-5"></a>
## v1\.9\.5
<a id="release-summary-19"></a>
### Release Summary
Bugfix release to fully support cryptography 35\.0\.0\.
<a id="bugfixes-19"></a>
### Bugfixes
* get\_certificate \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
* openssl\_csr\_info \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
* openssl\_csr\_info \- fix compatibility with the cryptography 35\.0\.0 release in PyOpenSSL backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/300](https\://github\.com/ansible\-collections/community\.crypto/pull/300)\)\.
* openssl\_pkcs12 \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/296](https\://github\.com/ansible\-collections/community\.crypto/pull/296)\)\.
* x509\_certificate\_info \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
* x509\_certificate\_info \- fix compatibility with the cryptography 35\.0\.0 release in PyOpenSSL backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/300](https\://github\.com/ansible\-collections/community\.crypto/pull/300)\)\.
<a id="v1-9-4"></a>
## v1\.9\.4
<a id="release-summary-20"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-20"></a>
### Bugfixes
* acme\_\* modules \- fix commands composed for OpenSSL backend to retrieve information on CSRs and certificates from stdin to use <code>/dev/stdin</code> instead of <code>\-</code>\. This is needed for OpenSSL 1\.0\.1 and 1\.0\.2\, apparently \([https\://github\.com/ansible\-collections/community\.crypto/pull/279](https\://github\.com/ansible\-collections/community\.crypto/pull/279)\)\.
* acme\_challenge\_cert\_helper \- only return exception when cryptography is not installed\, not when a too old version of it is installed\. This prevents Ansible\'s callback to crash \([https\://github\.com/ansible\-collections/community\.crypto/pull/281](https\://github\.com/ansible\-collections/community\.crypto/pull/281)\)\.
<a id="v1-9-3"></a>
## v1\.9\.3
<a id="release-summary-21"></a>
### Release Summary
Regular bugfix release\.
<a id="bugfixes-21"></a>
### Bugfixes
* openssl\_csr and openssl\_csr\_pipe \- make sure that Unicode strings are used to compare strings with the cryptography backend\. This fixes idempotency problems with non\-ASCII letters on Python 2 \([https\://github\.com/ansible\-collections/community\.crypto/issues/270](https\://github\.com/ansible\-collections/community\.crypto/issues/270)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/271](https\://github\.com/ansible\-collections/community\.crypto/pull/271)\)\.
<a id="v1-9-2"></a>
## v1\.9\.2
<a id="release-summary-22"></a>
### Release Summary
Bugfix release to fix the changelog\. No other change compared to 1\.9\.0\.
<a id="v1-9-1"></a>
## v1\.9\.1
<a id="release-summary-23"></a>
### Release Summary
Accidental 1\.9\.1 release\. Identical to 1\.9\.0\.
<a id="v1-9-0"></a>
## v1\.9\.0
<a id="release-summary-24"></a>
### Release Summary
Regular feature release\.
<a id="minor-changes-1"></a>
### Minor Changes
* get\_certificate \- added <code>starttls</code> option to retrieve certificates from servers which require clients to request an encrypted connection \([https\://github\.com/ansible\-collections/community\.crypto/pull/264](https\://github\.com/ansible\-collections/community\.crypto/pull/264)\)\.
* openssh\_keypair \- added <code>diff</code> support \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
<a id="bugfixes-22"></a>
### Bugfixes
* keypair\_backend module utils \- simplify code to pass sanity tests \([https\://github\.com/ansible\-collections/community\.crypto/pull/263](https\://github\.com/ansible\-collections/community\.crypto/pull/263)\)\.
* openssh\_keypair \- fixed <code>cryptography</code> backend to preserve original file permissions when regenerating a keypair requires existing files to be overwritten \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
* openssh\_keypair \- fixed error handling to restore original keypair if regeneration fails \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
* x509\_crl \- restore inherited function signature to pass sanity tests \([https\://github\.com/ansible\-collections/community\.crypto/pull/263](https\://github\.com/ansible\-collections/community\.crypto/pull/263)\)\.
<a id="v1-8-0"></a>
## v1\.8\.0
<a id="release-summary-25"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-2"></a>
### Minor Changes
* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.crypto/pull/253](https\://github\.com/ansible\-collections/community\.crypto/pull/253)\)\.
* openssh certificate module utils \- new module\_utils for parsing OpenSSH certificates \([https\://github\.com/ansible\-collections/community\.crypto/pull/246](https\://github\.com/ansible\-collections/community\.crypto/pull/246)\)\.
* openssh\_cert \- added <code>regenerate</code> option to validate additional certificate parameters which trigger regeneration of an existing certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/256](https\://github\.com/ansible\-collections/community\.crypto/pull/256)\)\.
* openssh\_cert \- adding <code>diff</code> support \([https\://github\.com/ansible\-collections/community\.crypto/pull/255](https\://github\.com/ansible\-collections/community\.crypto/pull/255)\)\.
<a id="bugfixes-23"></a>
### Bugfixes
* openssh\_cert \- fixed certificate generation to restore original certificate if an error is encountered \([https\://github\.com/ansible\-collections/community\.crypto/pull/255](https\://github\.com/ansible\-collections/community\.crypto/pull/255)\)\.
* openssh\_keypair \- fixed a bug that prevented custom file attributes being applied to public keys \([https\://github\.com/ansible\-collections/community\.crypto/pull/257](https\://github\.com/ansible\-collections/community\.crypto/pull/257)\)\.
<a id="v1-7-1"></a>
## v1\.7\.1
<a id="release-summary-26"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-24"></a>
### Bugfixes
* openssl\_pkcs12 \- fix crash when loading passphrase\-protected PKCS\#12 files with <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/issues/247](https\://github\.com/ansible\-collections/community\.crypto/issues/247)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/248](https\://github\.com/ansible\-collections/community\.crypto/pull/248)\)\.
<a id="v1-7-0"></a>
## v1\.7\.0
<a id="release-summary-27"></a>
### Release Summary
Regular feature and bugfix release\.
<a id="minor-changes-3"></a>
### Minor Changes
* cryptography\_openssh module utils \- new module\_utils for managing asymmetric keypairs and OpenSSH formatted/encoded asymmetric keypairs \([https\://github\.com/ansible\-collections/community\.crypto/pull/213](https\://github\.com/ansible\-collections/community\.crypto/pull/213)\)\.
* openssh\_keypair \- added <code>backend</code> parameter for selecting between the cryptography library or the OpenSSH binary for the execution of actions performed by <code>openssh\_keypair</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/236](https\://github\.com/ansible\-collections/community\.crypto/pull/236)\)\.
* openssh\_keypair \- added <code>passphrase</code> parameter for encrypting/decrypting OpenSSH private keys \([https\://github\.com/ansible\-collections/community\.crypto/pull/225](https\://github\.com/ansible\-collections/community\.crypto/pull/225)\)\.
* openssl\_csr \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* openssl\_csr\_info \- now returns <code>public\_key\_type</code> and <code>public\_key\_data</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/233](https\://github\.com/ansible\-collections/community\.crypto/pull/233)\)\.
* openssl\_csr\_info \- refactor module to allow code re\-use for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/204](https\://github\.com/ansible\-collections/community\.crypto/pull/204)\)\.
* openssl\_csr\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* openssl\_pkcs12 \- added option <code>select\_crypto\_backend</code> and a <code>cryptography</code> backend\. This requires cryptography 3\.0 or newer\, and does not support the <code>iter\_size</code> and <code>maciter\_size</code> options \([https\://github\.com/ansible\-collections/community\.crypto/pull/234](https\://github\.com/ansible\-collections/community\.crypto/pull/234)\)\.
* openssl\_privatekey \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* openssl\_privatekey\_info \- refactor module to allow code re\-use for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/205](https\://github\.com/ansible\-collections/community\.crypto/pull/205)\)\.
* openssl\_privatekey\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* openssl\_publickey \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* x509\_certificate \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* x509\_certificate\_info \- now returns <code>public\_key\_type</code> and <code>public\_key\_data</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/233](https\://github\.com/ansible\-collections/community\.crypto/pull/233)\)\.
* x509\_certificate\_info \- refactor module to allow code re\-use for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/206](https\://github\.com/ansible\-collections/community\.crypto/pull/206)\)\.
* x509\_certificate\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* x509\_crl \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
* x509\_crl\_info \- add <code>list\_revoked\_certificates</code> option to avoid enumerating all revoked certificates \([https\://github\.com/ansible\-collections/community\.crypto/pull/232](https\://github\.com/ansible\-collections/community\.crypto/pull/232)\)\.
* x509\_crl\_info \- refactor module to allow code re\-use for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/203](https\://github\.com/ansible\-collections/community\.crypto/pull/203)\)\.
<a id="bugfixes-25"></a>
### Bugfixes
* openssh\_keypair \- fix <code>check\_mode</code> to populate return values for existing keypairs \([https\://github\.com/ansible\-collections/community\.crypto/issues/113](https\://github\.com/ansible\-collections/community\.crypto/issues/113)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/230](https\://github\.com/ansible\-collections/community\.crypto/pull/230)\)\.
* various modules \- prevent crashes when modules try to set attributes on not yet existing files in check mode\. This will be fixed in ansible\-core 2\.12\, but it is not backported to every Ansible version we support \([https\://github\.com/ansible\-collections/community\.crypto/issue/242](https\://github\.com/ansible\-collections/community\.crypto/issue/242)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/243](https\://github\.com/ansible\-collections/community\.crypto/pull/243)\)\.
* x509\_certificate \- fix crash when <code>assertonly</code> provider is used and some error conditions should be reported \([https\://github\.com/ansible\-collections/community\.crypto/issues/240](https\://github\.com/ansible\-collections/community\.crypto/issues/240)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/241](https\://github\.com/ansible\-collections/community\.crypto/pull/241)\)\.
<a id="new-modules"></a>
### New Modules
* openssl\_publickey\_info \- Provide information for OpenSSL public keys
<a id="v1-6-2"></a>
## v1\.6\.2
<a id="release-summary-28"></a>
### Release Summary
Bugfix release\. Fixes compatibility issue of ACME modules with step\-ca\.
<a id="bugfixes-26"></a>
### Bugfixes
* acme\_\* modules \- avoid crashing for ACME servers where the <code>meta</code> directory key is not present \([https\://github\.com/ansible\-collections/community\.crypto/issues/220](https\://github\.com/ansible\-collections/community\.crypto/issues/220)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/221](https\://github\.com/ansible\-collections/community\.crypto/pull/221)\)\.
<a id="v1-6-1"></a>
## v1\.6\.1
<a id="release-summary-29"></a>
### Release Summary
Bugfix release\.
<a id="bugfixes-27"></a>
### Bugfixes
* acme\_\* modules \- fix wrong usages of <code>ACMEProtocolException</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/216](https\://github\.com/ansible\-collections/community\.crypto/pull/216)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/217](https\://github\.com/ansible\-collections/community\.crypto/pull/217)\)\.
<a id="v1-6-0"></a>
## v1\.6\.0
<a id="release-summary-30"></a>
### Release Summary
Fixes compatibility issues with the latest ansible\-core 2\.11 beta\, and contains a lot of internal refactoring for the ACME modules and support for private key passphrases for them\.
<a id="minor-changes-4"></a>
### Minor Changes
* acme module\_utils \- the <code>acme</code> module\_utils has been split up into several Python modules \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
* acme\_\* modules \- codebase refactor which should not be visible to end\-users \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
* acme\_\* modules \- support account key passphrases for <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/issues/197](https\://github\.com/ansible\-collections/community\.crypto/issues/197)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
* acme\_certificate\_revoke \- support revoking by private keys that are passphrase protected for <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
* acme\_challenge\_cert\_helper \- add <code>private\_key\_passphrase</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
<a id="deprecated-features"></a>
### Deprecated Features
* acme module\_utils \- the <code>acme</code> module\_utils \(<code>ansible\_collections\.community\.crypto\.plugins\.module\_utils\.acme</code>\) is deprecated and will be removed in community\.crypto 2\.0\.0\. Use the new Python modules in the <code>acme</code> package instead \(<code>ansible\_collections\.community\.crypto\.plugins\.module\_utils\.acme\.xxx</code>\) \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
<a id="bugfixes-28"></a>
### Bugfixes
* action\_module plugin helper \- make compatible with latest changes in ansible\-core 2\.11\.0b3 \([https\://github\.com/ansible\-collections/community\.crypto/pull/202](https\://github\.com/ansible\-collections/community\.crypto/pull/202)\)\.
* openssl\_privatekey\_pipe \- make compatible with latest changes in ansible\-core 2\.11\.0b3 \([https\://github\.com/ansible\-collections/community\.crypto/pull/202](https\://github\.com/ansible\-collections/community\.crypto/pull/202)\)\.
<a id="v1-5-0"></a>
## v1\.5\.0
<a id="release-summary-31"></a>
### Release Summary
Regular feature and bugfix release\. Deprecates a return value\.
<a id="minor-changes-5"></a>
### Minor Changes
* acme\_account\_info \- when <code>retrieve\_orders</code> is not <code>ignore</code> and the ACME server allows to query orders\, the new return value <code>order\_uris</code> is always populated with a list of URIs \([https\://github\.com/ansible\-collections/community\.crypto/pull/178](https\://github\.com/ansible\-collections/community\.crypto/pull/178)\)\.
* luks\_device \- allow to specify sector size for LUKS2 containers with new <code>sector\_size</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/193](https\://github\.com/ansible\-collections/community\.crypto/pull/193)\)\.
<a id="deprecated-features-1"></a>
### Deprecated Features
* acme\_account\_info \- when <code>retrieve\_orders\=url\_list</code>\, <code>orders</code> will no longer be returned in community\.crypto 2\.0\.0\. Use <code>order\_uris</code> instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/178](https\://github\.com/ansible\-collections/community\.crypto/pull/178)\)\.
<a id="bugfixes-29"></a>
### Bugfixes
* openssl\_csr \- no longer fails when comparing CSR without basic constraint when <code>basic\_constraints</code> is specified \([https\://github\.com/ansible\-collections/community\.crypto/issues/179](https\://github\.com/ansible\-collections/community\.crypto/issues/179)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/180](https\://github\.com/ansible\-collections/community\.crypto/pull/180)\)\.
<a id="v1-4-0"></a>
## v1\.4\.0
<a id="release-summary-32"></a>
### Release Summary
Release with several new features and bugfixes\.
<a id="minor-changes-6"></a>
### Minor Changes
* The ACME module\_utils has been relicensed back from the Simplified BSD License \([https\://opensource\.org/licenses/BSD\-2\-Clause](https\://opensource\.org/licenses/BSD\-2\-Clause)\) to the GPLv3\+ \(same license used by most other code in this collection\)\. This undoes a licensing change when the original GPLv3\+ licensed code was moved to module\_utils in [https\://github\.com/ansible/ansible/pull/40697](https\://github\.com/ansible/ansible/pull/40697) \([https\://github\.com/ansible\-collections/community\.crypto/pull/165](https\://github\.com/ansible\-collections/community\.crypto/pull/165)\)\.
* The <code>crypto/identify\.py</code> module\_utils has been renamed to <code>crypto/pem\.py</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/166](https\://github\.com/ansible\-collections/community\.crypto/pull/166)\)\.
* luks\_device \- <code>new\_keyfile</code>\, <code>new\_passphrase</code>\, <code>remove\_keyfile</code> and <code>remove\_passphrase</code> are now idempotent \([https\://github\.com/ansible\-collections/community\.crypto/issues/19](https\://github\.com/ansible\-collections/community\.crypto/issues/19)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/168](https\://github\.com/ansible\-collections/community\.crypto/pull/168)\)\.
* luks\_device \- allow to configure PBKDF \([https\://github\.com/ansible\-collections/community\.crypto/pull/163](https\://github\.com/ansible\-collections/community\.crypto/pull/163)\)\.
* openssl\_csr\, openssl\_csr\_pipe \- allow to specify CRL distribution endpoints with <code>crl\_distribution\_points</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/147](https\://github\.com/ansible\-collections/community\.crypto/issues/147)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/167](https\://github\.com/ansible\-collections/community\.crypto/pull/167)\)\.
* openssl\_pkcs12 \- allow to specify certificate bundles in <code>other\_certificates</code> by using new option <code>other\_certificates\_parse\_all</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/149](https\://github\.com/ansible\-collections/community\.crypto/issues/149)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/166](https\://github\.com/ansible\-collections/community\.crypto/pull/166)\)\.
<a id="bugfixes-30"></a>
### Bugfixes
* acme\_certificate \- error when requested challenge type is not found for non\-valid challenges\, instead of hanging on step 2 \([https\://github\.com/ansible\-collections/community\.crypto/issues/171](https\://github\.com/ansible\-collections/community\.crypto/issues/171)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/173](https\://github\.com/ansible\-collections/community\.crypto/pull/173)\)\.
<a id="v1-3-0"></a>
## v1\.3\.0
<a id="release-summary-33"></a>
### Release Summary
Contains new modules <code>openssl\_privatekey\_pipe</code>\, <code>openssl\_csr\_pipe</code> and <code>x509\_certificate\_pipe</code> which allow to create or update private keys\, CSRs and X\.509 certificates without having to write them to disk\.
<a id="minor-changes-7"></a>
### Minor Changes
* openssh\_cert \- add module parameter <code>use\_agent</code> to enable using signing keys stored in ssh\-agent \([https\://github\.com/ansible\-collections/community\.crypto/issues/116](https\://github\.com/ansible\-collections/community\.crypto/issues/116)\)\.
* openssl\_csr \- refactor module to allow code re\-use by openssl\_csr\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/123](https\://github\.com/ansible\-collections/community\.crypto/pull/123)\)\.
* openssl\_privatekey \- refactor module to allow code re\-use by openssl\_privatekey\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/119](https\://github\.com/ansible\-collections/community\.crypto/pull/119)\)\.
* openssl\_privatekey \- the elliptic curve <code>secp192r1</code> now triggers a security warning\. Elliptic curves of at least 224 bits should be used for new keys\; see [here](https\://cryptography\.io/en/latest/hazmat/primitives/asymmetric/ec\.html\#elliptic\-curves) \([https\://github\.com/ansible\-collections/community\.crypto/pull/132](https\://github\.com/ansible\-collections/community\.crypto/pull/132)\)\.
* x509\_certificate \- for the <code>selfsigned</code> provider\, a CSR is not required anymore\. If no CSR is provided\, the module behaves as if a minimal CSR which only contains the public key has been provided \([https\://github\.com/ansible\-collections/community\.crypto/issues/32](https\://github\.com/ansible\-collections/community\.crypto/issues/32)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/129](https\://github\.com/ansible\-collections/community\.crypto/pull/129)\)\.
* x509\_certificate \- refactor module to allow code re\-use by x509\_certificate\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/135](https\://github\.com/ansible\-collections/community\.crypto/pull/135)\)\.
<a id="bugfixes-31"></a>
### Bugfixes
* openssl\_pkcs12 \- report the correct state when <code>action</code> is <code>parse</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/143](https\://github\.com/ansible\-collections/community\.crypto/issues/143)\)\.
* support code \- improve handling of certificate and certificate signing request \(CSR\) loading with the <code>cryptography</code> backend when errors occur \([https\://github\.com/ansible\-collections/community\.crypto/issues/138](https\://github\.com/ansible\-collections/community\.crypto/issues/138)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/139](https\://github\.com/ansible\-collections/community\.crypto/pull/139)\)\.
* x509\_certificate \- fix <code>entrust</code> provider\, which was broken since community\.crypto 0\.1\.0 due to a feature added before the collection move \([https\://github\.com/ansible\-collections/community\.crypto/pull/135](https\://github\.com/ansible\-collections/community\.crypto/pull/135)\)\.
<a id="new-modules-1"></a>
### New Modules
* openssl\_csr\_pipe \- Generate OpenSSL Certificate Signing Request \(CSR\)
* openssl\_privatekey\_pipe \- Generate OpenSSL private keys without disk access
* x509\_certificate\_pipe \- Generate and/or check OpenSSL certificates
<a id="v1-2-0"></a>
## v1\.2\.0
<a id="release-summary-34"></a>
### Release Summary
Please note that this release fixes a security issue \(CVE\-2020\-25646\)\.
<a id="minor-changes-8"></a>
### Minor Changes
* acme\_certificate \- allow to pass CSR file as content with new option <code>csr\_content</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/115](https\://github\.com/ansible\-collections/community\.crypto/pull/115)\)\.
* x509\_certificate\_info \- add <code>fingerprints</code> return value which returns certificate fingerprints \([https\://github\.com/ansible\-collections/community\.crypto/pull/121](https\://github\.com/ansible\-collections/community\.crypto/pull/121)\)\.
<a id="security-fixes"></a>
### Security Fixes
* openssl\_csr \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
* openssl\_privatekey\_info \- the option <code>content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
* openssl\_publickey \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
* openssl\_signature \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
* x509\_certificate \- the options <code>privatekey\_content</code> and <code>ownca\_privatekey\_content</code> were not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
* x509\_crl \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
<a id="bugfixes-32"></a>
### Bugfixes
* openssl\_pkcs12 \- do not crash when reading PKCS\#12 file which has no private key and/or no main certificate \([https\://github\.com/ansible\-collections/community\.crypto/issues/103](https\://github\.com/ansible\-collections/community\.crypto/issues/103)\)\.
<a id="v1-1-1"></a>
## v1\.1\.1
<a id="release-summary-35"></a>
### Release Summary
Bugfixes for Ansible 2\.10\.0\.
<a id="bugfixes-33"></a>
### Bugfixes
* meta/runtime\.yml \- convert Ansible version numbers for old names of modules to collection version numbers \([https\://github\.com/ansible\-collections/community\.crypto/pull/108](https\://github\.com/ansible\-collections/community\.crypto/pull/108)\)\.
* openssl\_csr \- improve handling of IDNA errors \([https\://github\.com/ansible\-collections/community\.crypto/issues/105](https\://github\.com/ansible\-collections/community\.crypto/issues/105)\)\.
<a id="v1-1-0"></a>
## v1\.1\.0
<a id="release-summary-36"></a>
### Release Summary
Release for Ansible 2\.10\.0\.
<a id="minor-changes-9"></a>
### Minor Changes
* acme\_account \- add <code>external\_account\_binding</code> option to allow creation of ACME accounts with External Account Binding \([https\://github\.com/ansible\-collections/community\.crypto/issues/89](https\://github\.com/ansible\-collections/community\.crypto/issues/89)\)\.
* acme\_certificate \- allow new selector <code>test\_certificates\: first</code> for <code>select\_chain</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/102](https\://github\.com/ansible\-collections/community\.crypto/pull/102)\)\.
* cryptography backends \- support arbitrary dotted OIDs \([https\://github\.com/ansible\-collections/community\.crypto/issues/39](https\://github\.com/ansible\-collections/community\.crypto/issues/39)\)\.
* get\_certificate \- add support for SNI \([https\://github\.com/ansible\-collections/community\.crypto/issues/69](https\://github\.com/ansible\-collections/community\.crypto/issues/69)\)\.
* luks\_device \- add support for encryption options on container creation \([https\://github\.com/ansible\-collections/community\.crypto/pull/97](https\://github\.com/ansible\-collections/community\.crypto/pull/97)\)\.
* openssh\_cert \- add support for PKCS\#11 tokens \([https\://github\.com/ansible\-collections/community\.crypto/pull/95](https\://github\.com/ansible\-collections/community\.crypto/pull/95)\)\.
* openssl\_certificate \- the PyOpenSSL backend now uses 160 bits of randomness for serial numbers\, instead of a random number between 1000 and 99999\. Please note that this is not a high quality random number \([https\://github\.com/ansible\-collections/community\.crypto/issues/76](https\://github\.com/ansible\-collections/community\.crypto/issues/76)\)\.
* openssl\_csr \- add support for name constraints extension \([https\://github\.com/ansible\-collections/community\.crypto/issues/46](https\://github\.com/ansible\-collections/community\.crypto/issues/46)\)\.
* openssl\_csr\_info \- add support for name constraints extension \([https\://github\.com/ansible\-collections/community\.crypto/issues/46](https\://github\.com/ansible\-collections/community\.crypto/issues/46)\)\.
<a id="bugfixes-34"></a>
### Bugfixes
* acme\_inspect \- fix problem with Python 3\.5 that JSON was not decoded \([https\://github\.com/ansible\-collections/community\.crypto/issues/86](https\://github\.com/ansible\-collections/community\.crypto/issues/86)\)\.
* get\_certificate \- fix <code>ca\_cert</code> option handling when <code>proxy\_host</code> is used \([https\://github\.com/ansible\-collections/community\.crypto/pull/84](https\://github\.com/ansible\-collections/community\.crypto/pull/84)\)\.
* openssl\_\*\, x509\_\* modules \- fix handling of general names which refer to IP networks and not IP addresses \([https\://github\.com/ansible\-collections/community\.crypto/pull/92](https\://github\.com/ansible\-collections/community\.crypto/pull/92)\)\.
<a id="new-modules-2"></a>
### New Modules
* openssl\_signature \- Sign data with openssl
* openssl\_signature\_info \- Verify signatures with openssl
<a id="v1-0-0"></a>
## v1\.0\.0
<a id="release-summary-37"></a>
### Release Summary
This is the first proper release of the <code>community\.crypto</code> collection\. This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2\.9\.0\.
<a id="minor-changes-10"></a>
### Minor Changes
* luks\_device \- accept <code>passphrase</code>\, <code>new\_passphrase</code> and <code>remove\_passphrase</code>\.
* luks\_device \- add <code>keysize</code> parameter to set key size at LUKS container creation
* luks\_device \- added support to use UUIDs\, and labels with LUKS2 containers
* luks\_device \- added the <code>type</code> option that allows user explicit define the LUKS container format version
* openssh\_keypair \- instead of regenerating some broken or password protected keys\, fail the module\. Keys can still be regenerated by calling the module with <code>force\=yes</code>\.
* openssh\_keypair \- the <code>regenerate</code> option allows to configure the module\'s behavior when it should or needs to regenerate private keys\.
* openssl\_\* modules \- the cryptography backend now properly supports <code>dirName</code>\, <code>otherName</code> and <code>RID</code> \(Registered ID\) names\.
* openssl\_certificate \- Add option for changing which ACME directory to use with acme\-tiny\. Set the default ACME directory to Let\'s Encrypt instead of using acme\-tiny\'s default\. \(acme\-tiny also uses Let\'s Encrypt at the time being\, so no action should be neccessary\.\)
* openssl\_certificate \- Change the required version of acme\-tiny to \>\= 4\.0\.0
* openssl\_certificate \- allow to provide content of some input files via the <code>csr\_content</code>\, <code>privatekey\_content</code>\, <code>ownca\_privatekey\_content</code> and <code>ownca\_content</code> options\.
* openssl\_certificate \- allow to return the existing/generated certificate directly as <code>certificate</code> by setting <code>return\_content</code> to <code>yes</code>\.
* openssl\_certificate\_info \- allow to provide certificate content via <code>content</code> option \([https\://github\.com/ansible/ansible/issues/64776](https\://github\.com/ansible/ansible/issues/64776)\)\.
* openssl\_csr \- Add support for specifying the SAN <code>otherName</code> value in the OpenSSL ASN\.1 UTF8 string format\, <code>otherName\:\<OID\>\;UTF8\:string value</code>\.
* openssl\_csr \- allow to provide private key content via <code>private\_key\_content</code> option\.
* openssl\_csr \- allow to return the existing/generated CSR directly as <code>csr</code> by setting <code>return\_content</code> to <code>yes</code>\.
* openssl\_csr\_info \- allow to provide CSR content via <code>content</code> option\.
* openssl\_dhparam \- allow to return the existing/generated DH params directly as <code>dhparams</code> by setting <code>return\_content</code> to <code>yes</code>\.
* openssl\_dhparam \- now supports a <code>cryptography</code>\-based backend\. Auto\-detection can be overwritten with the <code>select\_crypto\_backend</code> option\.
* openssl\_pkcs12 \- allow to return the existing/generated PKCS\#12 directly as <code>pkcs12</code> by setting <code>return\_content</code> to <code>yes</code>\.
* openssl\_privatekey \- add <code>format</code> and <code>format\_mismatch</code> options\.
* openssl\_privatekey \- allow to return the existing/generated private key directly as <code>privatekey</code> by setting <code>return\_content</code> to <code>yes</code>\.
* openssl\_privatekey \- the <code>regenerate</code> option allows to configure the module\'s behavior when it should or needs to regenerate private keys\.
* openssl\_privatekey\_info \- allow to provide private key content via <code>content</code> option\.
* openssl\_publickey \- allow to provide private key content via <code>private\_key\_content</code> option\.
* openssl\_publickey \- allow to return the existing/generated public key directly as <code>publickey</code> by setting <code>return\_content</code> to <code>yes</code>\.
<a id="deprecated-features-2"></a>
### Deprecated Features
* openssl\_csr \- all values for the <code>version</code> option except <code>1</code> are deprecated\. The value 1 denotes the current only standardized CSR version\.
<a id="removed-features-previously-deprecated"></a>
### Removed Features \(previously deprecated\)
* The <code>letsencrypt</code> module has been removed\. Use <code>acme\_certificate</code> instead\.
<a id="bugfixes-35"></a>
### Bugfixes
* ACME modules\: fix bug in ACME v1 account update code
* ACME modules\: make sure some connection errors are handled properly
* ACME modules\: support Buypass\' ACME v1 endpoint
* acme\_certificate \- fix crash when module is used with Python 2\.x\.
* acme\_certificate \- fix misbehavior when ACME v1 is used with <code>modify\_account</code> set to <code>false</code>\.
* ecs\_certificate \- Always specify header <code>connection\: keep\-alive</code> for ECS API connections\.
* ecs\_certificate \- Fix formatting of contents of <code>full\_chain\_path</code>\.
* get\_certificate \- Fix cryptography backend when pyopenssl is unavailable \([https\://github\.com/ansible/ansible/issues/67900](https\://github\.com/ansible/ansible/issues/67900)\)
* openssh\_keypair \- add logic to avoid breaking password protected keys\.
* openssh\_keypair \- fixes idempotence issue with public key \([https\://github\.com/ansible/ansible/issues/64969](https\://github\.com/ansible/ansible/issues/64969)\)\.
* openssh\_keypair \- public key\'s file attributes \(permissions\, owner\, group\, etc\.\) are now set to the same values as the private key\.
* openssl\_\* modules \- prevent crash on fingerprint determination in FIPS mode \([https\://github\.com/ansible/ansible/issues/67213](https\://github\.com/ansible/ansible/issues/67213)\)\.
* openssl\_certificate \- When provider is <code>entrust</code>\, use a <code>connection\: keep\-alive</code> header for ECS API connections\.
* openssl\_certificate \- <code>provider</code> option was documented as required\, but it was not checked whether it was provided\. It is now only required when <code>state</code> is <code>present</code>\.
* openssl\_certificate \- fix <code>assertonly</code> provider certificate verification\, causing \'private key mismatch\' and \'subject mismatch\' errors\.
* openssl\_certificate and openssl\_csr \- fix Ed25519 and Ed448 private key support for <code>cryptography</code> backend\. This probably needs at least cryptography 2\.8\, since older versions have problems with signing certificates or CSRs with such keys\. \([https\://github\.com/ansible/ansible/issues/59039](https\://github\.com/ansible/ansible/issues/59039)\, PR [https\://github\.com/ansible/ansible/pull/63984](https\://github\.com/ansible/ansible/pull/63984)\)
* openssl\_csr \- a warning is issued if an unsupported value for <code>version</code> is used for the <code>cryptography</code> backend\.
* openssl\_csr \- the module will now enforce that <code>privatekey\_path</code> is specified when <code>state\=present</code>\.
* openssl\_publickey \- fix a module crash caused when pyOpenSSL is not installed \([https\://github\.com/ansible/ansible/issues/67035](https\://github\.com/ansible/ansible/issues/67035)\)\.
<a id="new-modules-3"></a>
### New Modules
* ecs\_domain \- Request validation of a domain with the Entrust Certificate Services \(ECS\) API
* x509\_crl \- Generate Certificate Revocation Lists \(CRLs\)
* x509\_crl\_info \- Retrieve information on Certificate Revocation Lists \(CRLs\)

3
CHANGELOG.md.license Normal file
View File

@@ -0,0 +1,3 @@
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: Ansible Project

View File

@@ -4,6 +4,303 @@ Community Crypto Release Notes
.. contents:: Topics .. contents:: Topics
v1.9.25
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- crypto.math module utils - change return values for ``quick_is_not_prime()`` for special cases that do not appear when using the collection (https://github.com/ansible-collections/community.crypto/pull/733).
- ecs_certificate - fixed ``csr`` option to be empty and allow renewal of a specific certificate according to the Renewal Information specification (https://github.com/ansible-collections/community.crypto/pull/740).
v1.9.24
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssl_dhparam - was using an internal function instead of the public API to load DH param files when using the ``cryptography`` backend. The internal function was removed in cryptography 42.0.0. The module now uses the public API, which has been available since support for DH params was added to cryptography (https://github.com/ansible-collections/community.crypto/pull/698).
- openssl_privatekey_info - ``check_consistency=true`` no longer works for RSA keys with cryptography 42.0.0+ (https://github.com/ansible-collections/community.crypto/pull/701).
- x509_certificate - when using the PyOpenSSL backend with ``provider=assertonly``, better handle unexpected errors when validating private keys (https://github.com/ansible-collections/community.crypto/pull/704).
v1.9.23
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssl_pkcs12 - modify autodetect to not detect pyOpenSSL >= 23.3.0, which removed PKCS#12 support (https://github.com/ansible-collections/community.crypto/pull/666).
v1.9.22
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssh_keypair - always generate a new key pair if the private key does not exist. Previously, the module would fail when ``regenerate=fail`` without an existing key, contradicting the documentation (https://github.com/ansible-collections/community.crypto/pull/598).
v1.9.21
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- action plugin helper - fix handling of deprecations for ansible-core 2.14.2 (https://github.com/ansible-collections/community.crypto/pull/572).
- openssl_csr, openssl_csr_pipe - prevent invalid values for ``crl_distribution_points`` that do not have one of ``full_name``, ``relative_name``, and ``crl_issuer`` (https://github.com/ansible-collections/community.crypto/pull/560).
v1.9.20
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssl_publickey_info - do not crash with internal error when public key cannot be parsed (https://github.com/ansible-collections/community.crypto/pull/551).
v1.9.19
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssl_privatekey_pipe - ensure compatibility with newer versions of ansible-core (https://github.com/ansible-collections/community.crypto/pull/515).
v1.9.18
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssl_pkcs12 - when using the pyOpenSSL backend, do not crash when trying to read non-existing other certificates (https://github.com/ansible-collections/community.crypto/issues/486, https://github.com/ansible-collections/community.crypto/pull/487).
v1.9.17
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- Include ``Apache-2.0.txt`` file for ``plugins/module_utils/crypto/_obj2txt.py`` and ``plugins/module_utils/crypto/_objects_data.py``.
- openssl_csr - the module no longer crashes with 'permitted_subtrees/excluded_subtrees must be a non-empty list or None' if only one of ``name_constraints_permitted`` and ``name_constraints_excluded`` is provided (https://github.com/ansible-collections/community.crypto/issues/481).
- x509_crl - do not crash when signing CRL with Ed25519 or Ed448 keys (https://github.com/ansible-collections/community.crypto/issues/473, https://github.com/ansible-collections/community.crypto/pull/474).
v1.9.16
=======
Release Summary
---------------
Maintenance and bugfix release.
Bugfixes
--------
- Include ``simplified_bsd.txt`` license file for the ECS module utils.
- certificate_complete_chain - do not stop execution if an unsupported signature algorithm is encountered; warn instead (https://github.com/ansible-collections/community.crypto/pull/457).
v1.9.15
=======
Release Summary
---------------
Maintenance release.
Bugfixes
--------
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
v1.9.14
=======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- Make collection more robust when PyOpenSSL is used with an incompatible cryptography version (https://github.com/ansible-collections/community.crypto/pull/446).
- openssh_* modules - fix exception handling to report traceback to users for enhanced traceability (https://github.com/ansible-collections/community.crypto/pull/417).
- x509_crl - fix crash when ``issuer`` for a revoked certificate is specified (https://github.com/ansible-collections/community.crypto/pull/441).
v1.9.13
=======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- luks_device - fix parsing of ``lsblk`` output when device name ends with ``crypt`` (https://github.com/ansible-collections/community.crypto/issues/409, https://github.com/ansible-collections/community.crypto/pull/410).
v1.9.12
=======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- certificate_complete_chain - allow multiple potential intermediate certificates to have the same subject (https://github.com/ansible-collections/community.crypto/issues/399, https://github.com/ansible-collections/community.crypto/pull/403).
- x509_certificate - for the ``ownca`` provider, check whether the CA private key actually belongs to the CA certificate. This fix only covers the ``cryptography`` backend, not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - regenerate certificate when the CA's public key changes for ``provider=ownca``. This fix only covers the ``cryptography`` backend, not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - regenerate certificate when the CA's subject changes for ``provider=ownca`` (https://github.com/ansible-collections/community.crypto/issues/400, https://github.com/ansible-collections/community.crypto/pull/402).
- x509_certificate - regenerate certificate when the private key changes for ``provider=selfsigned``. This fix only covers the ``cryptography`` backend, not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
Known Issues
------------
- x509_certificate - when using the ``ownca`` provider with the ``pyopenssl`` backend, changing the CA's public key does not cause regeneration of the certificate (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - when using the ``ownca`` provider with the ``pyopenssl`` backend, it is possible to specify a CA private key which is not related to the CA certificate (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - when using the ``selfsigned`` provider with the ``pyopenssl`` backend, changing the private key does not cause regeneration of the certificate (https://github.com/ansible-collections/community.crypto/pull/407).
v1.9.11
=======
Release Summary
---------------
Bugfix release.
Bugfixes
--------
- openssh_cert - fixed false ``changed`` status for ``host`` certificates when using ``full_idempotence`` (https://github.com/ansible-collections/community.crypto/issues/395, https://github.com/ansible-collections/community.crypto/pull/396).
v1.9.10
=======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- luks_devices - set ``LANG`` and similar environment variables to avoid translated output, which can break some of the module's functionality like key management (https://github.com/ansible-collections/community.crypto/pull/388, https://github.com/ansible-collections/community.crypto/issues/385).
v1.9.9
======
Bugfixes
--------
- Various modules and plugins - use vendored version of ``distutils.version`` instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.crypto/pull/353).
- certificate_complete_chain - do not append root twice if the chain already ends with a root certificate (https://github.com/ansible-collections/community.crypto/pull/360).
- certificate_complete_chain - do not hang when infinite loop is found (https://github.com/ansible-collections/community.crypto/issues/355, https://github.com/ansible-collections/community.crypto/pull/360).
v1.9.8
======
Release Summary
---------------
Documentation fix release. No actual code changes.
v1.9.7
======
Release Summary
---------------
Bugfix release with extra forward compatibility for newer versions of cryptography.
Minor Changes
-------------
- acme_* modules - fix usage of ``fetch_url`` with changes in latest ansible-core ``devel`` branch (https://github.com/ansible-collections/community.crypto/pull/339).
Bugfixes
--------
- acme_certificate - avoid passing multiple certificates to ``cryptography``'s X.509 certificate loader when ``fullchain_dest`` is used (https://github.com/ansible-collections/community.crypto/pull/324).
- get_certificate, openssl_csr_info, x509_certificate_info - add fallback code for extension parsing that works with cryptography 36.0.0 and newer. This code re-serializes de-serialized extensions and thus can return slightly different values if the extension in the original CSR resp. certificate was not canonicalized correctly. This code is currently used as a fallback if the existing code stops working, but we will switch it to be the main code in a future release (https://github.com/ansible-collections/community.crypto/pull/331).
- luks_device - now also runs a built-in LUKS signature cleaner on ``state=absent`` to make sure that also the secondary LUKS2 header is wiped when older versions of wipefs are used (https://github.com/ansible-collections/community.crypto/issues/326, https://github.com/ansible-collections/community.crypto/pull/327).
- openssl_pkcs12 - use new PKCS#12 deserialization infrastructure from cryptography 36.0.0 if available (https://github.com/ansible-collections/community.crypto/pull/302).
v1.9.6
======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- cryptography backend - improve Unicode handling for Python 2 (https://github.com/ansible-collections/community.crypto/pull/313).
v1.9.5
======
Release Summary
---------------
Bugfix release to fully support cryptography 35.0.0.
Bugfixes
--------
- get_certificate - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
- openssl_pkcs12 - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/296).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
v1.9.4 v1.9.4
====== ======
@@ -257,7 +554,6 @@ Release Summary
Contains new modules ``openssl_privatekey_pipe``, ``openssl_csr_pipe`` and ``x509_certificate_pipe`` which allow to create or update private keys, CSRs and X.509 certificates without having to write them to disk. Contains new modules ``openssl_privatekey_pipe``, ``openssl_csr_pipe`` and ``x509_certificate_pipe`` which allow to create or update private keys, CSRs and X.509 certificates without having to write them to disk.
Minor Changes Minor Changes
------------- -------------
@@ -333,7 +629,6 @@ Release Summary
Release for Ansible 2.10.0. Release for Ansible 2.10.0.
Minor Changes Minor Changes
------------- -------------
@@ -368,7 +663,6 @@ Release Summary
This is the first proper release of the ``community.crypto`` collection. This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2.9.0. This is the first proper release of the ``community.crypto`` collection. This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2.9.0.
Minor Changes Minor Changes
------------- -------------

48
PSF-license.txt Normal file
View File

@@ -0,0 +1,48 @@
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
All Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.

View File

@@ -11,7 +11,7 @@ Please note that this collection does **not** support Windows targets.
## Tested with Ansible ## Tested with Ansible
Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11 and ansible-core 2.12 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported. Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12 and ansible-core 2.13 releases. Ansible versions before 2.9.10 are not supported.
## External requirements ## External requirements
@@ -85,7 +85,7 @@ See [Ansible's dev guide](https://docs.ansible.com/ansible/devel/dev_guide/devel
## Release notes ## Release notes
See the [changelog](https://github.com/ansible-collections/community.crypto/blob/main/CHANGELOG.rst). See the [changelog](https://github.com/ansible-collections/community.crypto/blob/stable-1/CHANGELOG.md).
## Roadmap ## Roadmap

View File

@@ -528,6 +528,148 @@ releases:
changes: changes:
release_summary: Accidental 1.9.1 release. Identical to 1.9.0. release_summary: Accidental 1.9.1 release. Identical to 1.9.0.
release_date: '2021-08-30' release_date: '2021-08-30'
1.9.10:
changes:
bugfixes:
- luks_devices - set ``LANG`` and similar environment variables to avoid translated
output, which can break some of the module's functionality like key management
(https://github.com/ansible-collections/community.crypto/pull/388, https://github.com/ansible-collections/community.crypto/issues/385).
release_summary: Regular bugfix release.
fragments:
- 1.9.10.yml
- 388-luks_device-i18n.yml
release_date: '2022-02-01'
1.9.11:
changes:
bugfixes:
- openssh_cert - fixed false ``changed`` status for ``host`` certificates when
using ``full_idempotence`` (https://github.com/ansible-collections/community.crypto/issues/395,
https://github.com/ansible-collections/community.crypto/pull/396).
release_summary: Bugfix release.
fragments:
- 1.9.11.yml
- 396-openssh_cert-host-cert-idempotence-fix.yml
release_date: '2022-02-05'
1.9.12:
changes:
bugfixes:
- certificate_complete_chain - allow multiple potential intermediate certificates
to have the same subject (https://github.com/ansible-collections/community.crypto/issues/399,
https://github.com/ansible-collections/community.crypto/pull/403).
- x509_certificate - for the ``ownca`` provider, check whether the CA private
key actually belongs to the CA certificate. This fix only covers the ``cryptography``
backend, not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - regenerate certificate when the CA's public key changes
for ``provider=ownca``. This fix only covers the ``cryptography`` backend,
not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - regenerate certificate when the CA's subject changes for
``provider=ownca`` (https://github.com/ansible-collections/community.crypto/issues/400,
https://github.com/ansible-collections/community.crypto/pull/402).
- x509_certificate - regenerate certificate when the private key changes for
``provider=selfsigned``. This fix only covers the ``cryptography`` backend,
not the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/407).
known_issues:
- x509_certificate - when using the ``ownca`` provider with the ``pyopenssl``
backend, changing the CA's public key does not cause regeneration of the certificate
(https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - when using the ``ownca`` provider with the ``pyopenssl``
backend, it is possible to specify a CA private key which is not related to
the CA certificate (https://github.com/ansible-collections/community.crypto/pull/407).
- x509_certificate - when using the ``selfsigned`` provider with the ``pyopenssl``
backend, changing the private key does not cause regeneration of the certificate
(https://github.com/ansible-collections/community.crypto/pull/407).
release_summary: Regular bugfix release.
fragments:
- 1.9.12.yml
- 402-x509_certificate-ownca-subject.yml
- 403-certificate_complete_chain-same-subject.yml
- 407-x509_certificate-signature.yml
release_date: '2022-02-21'
1.9.13:
changes:
bugfixes:
- luks_device - fix parsing of ``lsblk`` output when device name ends with ``crypt``
(https://github.com/ansible-collections/community.crypto/issues/409, https://github.com/ansible-collections/community.crypto/pull/410).
release_summary: Regular bugfix release.
fragments:
- 1.9.13.yml
- 410-luks_device-lsblk-parsing.yml
release_date: '2022-03-04'
1.9.14:
changes:
bugfixes:
- Make collection more robust when PyOpenSSL is used with an incompatible cryptography
version (https://github.com/ansible-collections/community.crypto/pull/446).
- openssh_* modules - fix exception handling to report traceback to users for
enhanced traceability (https://github.com/ansible-collections/community.crypto/pull/417).
- x509_crl - fix crash when ``issuer`` for a revoked certificate is specified
(https://github.com/ansible-collections/community.crypto/pull/441).
release_summary: Regular bugfix release.
fragments:
- 1.9.14.yml
- 417-openssh_modules-fix-exception-reporting.yml
- 441-x509-crl-cert-issuer.yml
- 446-fix.yml
release_date: '2022-05-09'
1.9.15:
changes:
bugfixes:
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
release_summary: Maintenance release.
fragments:
- 1.9.15.yml
- psf-license.yml
release_date: '2022-05-16'
1.9.16:
changes:
bugfixes:
- Include ``simplified_bsd.txt`` license file for the ECS module utils.
- certificate_complete_chain - do not stop execution if an unsupported signature
algorithm is encountered; warn instead (https://github.com/ansible-collections/community.crypto/pull/457).
release_summary: Maintenance and bugfix release.
fragments:
- 1.9.16.yml
- 457-certificate_complete_chain-unsupported-algorithm.yml
- simplified-bsd-license.yml
release_date: '2022-06-02'
1.9.17:
changes:
bugfixes:
- Include ``Apache-2.0.txt`` file for ``plugins/module_utils/crypto/_obj2txt.py``
and ``plugins/module_utils/crypto/_objects_data.py``.
- openssl_csr - the module no longer crashes with 'permitted_subtrees/excluded_subtrees
must be a non-empty list or None' if only one of ``name_constraints_permitted``
and ``name_constraints_excluded`` is provided (https://github.com/ansible-collections/community.crypto/issues/481).
- x509_crl - do not crash when signing CRL with Ed25519 or Ed448 keys (https://github.com/ansible-collections/community.crypto/issues/473,
https://github.com/ansible-collections/community.crypto/pull/474).
release_summary: Bugfix release.
fragments:
- 1.9.17.yml
- 474-x509_crl-ed25519-ed448.yml
- 481-fix-excluded_subtrees-must-be-a-non-empty-list-or-None.yml
- apache-license.yml
release_date: '2022-06-17'
1.9.18:
changes:
bugfixes:
- openssl_pkcs12 - when using the pyOpenSSL backend, do not crash when trying
to read non-existing other certificates (https://github.com/ansible-collections/community.crypto/issues/486,
https://github.com/ansible-collections/community.crypto/pull/487).
release_summary: Bugfix release.
fragments:
- 1.9.18.yml
- 487-openssl_pkcs12-other-certs-crash.yml
release_date: '2022-07-09'
1.9.19:
changes:
bugfixes:
- openssl_privatekey_pipe - ensure compatibility with newer versions of ansible-core
(https://github.com/ansible-collections/community.crypto/pull/515).
release_summary: Bugfix release.
fragments:
- 1.9.19.yml
- 515-action-module-compat.yml
release_date: '2022-11-01'
1.9.2: 1.9.2:
changes: changes:
release_summary: Bugfix release to fix the changelog. No other change compared release_summary: Bugfix release to fix the changelog. No other change compared
@@ -535,6 +677,83 @@ releases:
fragments: fragments:
- 1.9.2.yml - 1.9.2.yml
release_date: '2021-08-30' release_date: '2021-08-30'
1.9.20:
changes:
bugfixes:
- openssl_publickey_info - do not crash with internal error when public key
cannot be parsed (https://github.com/ansible-collections/community.crypto/pull/551).
release_summary: Bugfix release.
fragments:
- 1.9.20.yml
- 551-publickey-info.yml
release_date: '2023-01-01'
1.9.21:
changes:
bugfixes:
- action plugin helper - fix handling of deprecations for ansible-core 2.14.2
(https://github.com/ansible-collections/community.crypto/pull/572).
- openssl_csr, openssl_csr_pipe - prevent invalid values for ``crl_distribution_points``
that do not have one of ``full_name``, ``relative_name``, and ``crl_issuer``
(https://github.com/ansible-collections/community.crypto/pull/560).
release_summary: Bugfix release.
fragments:
- 1.9.21.yml
- 560-openssl_csr-crl_distribution_points.yml
- 572-action-module.yml
release_date: '2023-04-16'
1.9.22:
changes:
bugfixes:
- openssh_keypair - always generate a new key pair if the private key does not
exist. Previously, the module would fail when ``regenerate=fail`` without
an existing key, contradicting the documentation (https://github.com/ansible-collections/community.crypto/pull/598).
release_summary: Bugfix release.
fragments:
- 1.9.22.yml
- 598-openssh_keypair-generate-new-key.yml
release_date: '2023-06-15'
1.9.23:
changes:
bugfixes:
- openssl_pkcs12 - modify autodetect to not detect pyOpenSSL >= 23.3.0, which
removed PKCS#12 support (https://github.com/ansible-collections/community.crypto/pull/666).
release_summary: Bugfix release.
fragments:
- 1.9.23.yml
- pkcs12.yml
release_date: '2023-10-29'
1.9.24:
changes:
bugfixes:
- openssl_dhparam - was using an internal function instead of the public API
to load DH param files when using the ``cryptography`` backend. The internal
function was removed in cryptography 42.0.0. The module now uses the public
API, which has been available since support for DH params was added to cryptography
(https://github.com/ansible-collections/community.crypto/pull/698).
- openssl_privatekey_info - ``check_consistency=true`` no longer works for RSA
keys with cryptography 42.0.0+ (https://github.com/ansible-collections/community.crypto/pull/701).
- x509_certificate - when using the PyOpenSSL backend with ``provider=assertonly``,
better handle unexpected errors when validating private keys (https://github.com/ansible-collections/community.crypto/pull/704).
release_summary: Bugfix release.
fragments:
- 1.9.24.yml
- 698-openssl_dhparam-cryptography.yml
- 701-private_key_info-consistency.yml
- 704-x509_certificate-assertonly-privatekey.yml
release_date: '2024-01-27'
1.9.25:
changes:
bugfixes:
- crypto.math module utils - change return values for ``quick_is_not_prime()``
for special cases that do not appear when using the collection (https://github.com/ansible-collections/community.crypto/pull/733).
- ecs_certificate - fixed ``csr`` option to be empty and allow renewal of a
specific certificate according to the Renewal Information specification (https://github.com/ansible-collections/community.crypto/pull/740).
release_summary: Bugfix release.
fragments:
- 1.9.25.yml
- 733-math-prime.yml
- 740-ecs_certificate-renewal-without-csr.yml
release_date: '2024-05-20'
1.9.3: 1.9.3:
changes: changes:
bugfixes: bugfixes:
@@ -562,3 +781,82 @@ releases:
- 279-acme-openssl.yml - 279-acme-openssl.yml
- 282-acme_challenge_cert_helper-error.yml - 282-acme_challenge_cert_helper-error.yml
release_date: '2021-09-28' release_date: '2021-09-28'
1.9.5:
changes:
bugfixes:
- get_certificate - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release
(https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release
in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
- openssl_pkcs12 - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/296).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release
(https://github.com/ansible-collections/community.crypto/pull/294).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release
in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
release_summary: Bugfix release to fully support cryptography 35.0.0.
fragments:
- 1.9.5.yml
- 294-cryptography-35.0.0.yml
- 296-openssl_pkcs12-cryptography-35.yml
- 300-pyopenssl-cryptography-35.yml
release_date: '2021-10-06'
1.9.6:
changes:
bugfixes:
- cryptography backend - improve Unicode handling for Python 2 (https://github.com/ansible-collections/community.crypto/pull/313).
release_summary: Regular bugfix release.
fragments:
- 1.9.6.yml
- 313-unicode-names.yml
release_date: '2021-10-30'
1.9.7:
changes:
bugfixes:
- acme_certificate - avoid passing multiple certificates to ``cryptography``'s
X.509 certificate loader when ``fullchain_dest`` is used (https://github.com/ansible-collections/community.crypto/pull/324).
- get_certificate, openssl_csr_info, x509_certificate_info - add fallback code
for extension parsing that works with cryptography 36.0.0 and newer. This
code re-serializes de-serialized extensions and thus can return slightly different
values if the extension in the original CSR resp. certificate was not canonicalized
correctly. This code is currently used as a fallback if the existing code
stops working, but we will switch it to be the main code in a future release
(https://github.com/ansible-collections/community.crypto/pull/331).
- luks_device - now also runs a built-in LUKS signature cleaner on ``state=absent``
to make sure that also the secondary LUKS2 header is wiped when older versions
of wipefs are used (https://github.com/ansible-collections/community.crypto/issues/326,
https://github.com/ansible-collections/community.crypto/pull/327).
- openssl_pkcs12 - use new PKCS#12 deserialization infrastructure from cryptography
36.0.0 if available (https://github.com/ansible-collections/community.crypto/pull/302).
minor_changes:
- acme_* modules - fix usage of ``fetch_url`` with changes in latest ansible-core
``devel`` branch (https://github.com/ansible-collections/community.crypto/pull/339).
release_summary: Bugfix release with extra forward compatibility for newer versions
of cryptography.
fragments:
- 1.9.7.yml
- 302-openssl_pkcs12-cryptography-36.0.0.yml
- 324-acme_certificate-fullchain.yml
- 327-luks_device-wipe.yml
- 331-cryptography-extensions.yml
- fetch_url-devel.yml
release_date: '2021-11-22'
1.9.8:
changes:
release_summary: Documentation fix release. No actual code changes.
fragments:
- 1.9.8.yml
release_date: '2021-12-13'
1.9.9:
changes:
bugfixes:
- Various modules and plugins - use vendored version of ``distutils.version``
instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.crypto/pull/353).
- certificate_complete_chain - do not append root twice if the chain already
ends with a root certificate (https://github.com/ansible-collections/community.crypto/pull/360).
- certificate_complete_chain - do not hang when infinite loop is found (https://github.com/ansible-collections/community.crypto/issues/355,
https://github.com/ansible-collections/community.crypto/pull/360).
fragments:
- 353-distutils.version.yml
- 360-certificate_complete_chain-loop.yml
release_date: '2022-01-11'

View File

@@ -6,6 +6,9 @@ keep_fragments: false
mention_ancestor: true mention_ancestor: true
new_plugins_after_name: removed_features new_plugins_after_name: removed_features
notesdir: fragments notesdir: fragments
output_formats:
- md
- rst
prelude_section_name: release_summary prelude_section_name: release_summary
prelude_section_title: Release Summary prelude_section_title: Release Summary
sections: sections:

View File

@@ -3,7 +3,7 @@
How to create a small CA How to create a small CA
======================== ========================
The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create your own small CA and how to use it to sign certificates. The `community.crypto collection <https://galaxy.ansible.com/ui/repo/published/community/crypto/>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create your own small CA and how to use it to sign certificates.
In all examples, we assume that the CA's private key is password protected, where the password is provided in the ``secret_ca_passphrase`` variable. In all examples, we assume that the CA's private key is password protected, where the password is provided in the ``secret_ca_passphrase`` variable.
@@ -71,7 +71,7 @@ In the following example, we assume that the certificate to sign (including its
- name: Sign certificate with our CA - name: Sign certificate with our CA
community.crypto.x509_certificate_pipe: community.crypto.x509_certificate_pipe:
csr_content: "{{ ca_csr.csr }}" csr_content: "{{ csr.csr }}"
provider: ownca provider: ownca
ownca_path: /path/to/ca-certificate.pem ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key ownca_privatekey_path: /path/to/ca-certificate.key
@@ -128,7 +128,7 @@ Please note that the above procedure is **not idempotent**. The following extend
- name: Sign certificate with our CA - name: Sign certificate with our CA
community.crypto.x509_certificate_pipe: community.crypto.x509_certificate_pipe:
content: "{{ (certificate.content | b64decode) if certificate_exists.stat.exists else omit }}" content: "{{ (certificate.content | b64decode) if certificate_exists.stat.exists else omit }}"
csr_content: "{{ ca_csr.csr }}" csr_content: "{{ csr.csr }}"
provider: ownca provider: ownca
ownca_path: /path/to/ca-certificate.pem ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key ownca_privatekey_path: /path/to/ca-certificate.key

View File

@@ -3,7 +3,7 @@
How to create self-signed certificates How to create self-signed certificates
====================================== ======================================
The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create self-signed certificates. The `community.crypto collection <https://galaxy.ansible.com/ui/repo/published/community/crypto/>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create self-signed certificates.
For creating any kind of certificate, you always have to start with a private key. You can use the :ref:`community.crypto.openssl_privatekey module <ansible_collections.community.crypto.openssl_privatekey_module>` to create a private key. If you only specify ``path``, the default parameters will be used. This will result in a 4096 bit RSA private key: For creating any kind of certificate, you always have to start with a private key. You can use the :ref:`community.crypto.openssl_privatekey module <ansible_collections.community.crypto.openssl_privatekey_module>` to create a private key. If you only specify ``path``, the default parameters will be used. This will result in a 4096 bit RSA private key:

View File

@@ -1,6 +1,6 @@
namespace: community namespace: community
name: crypto name: crypto
version: 1.9.4 version: 1.9.25
readme: README.md readme: README.md
authors: authors:
- Ansible (github.com/ansible) - Ansible (github.com/ansible)

View File

@@ -45,7 +45,7 @@ options:
type: path type: path
privatekey_content: privatekey_content:
description: description:
- Path to the private key to use when signing the certificate. - Content of the private key to use when signing the certificate.
- This is mutually exclusive with I(privatekey_path). - This is mutually exclusive with I(privatekey_path).
type: str type: str
@@ -457,8 +457,8 @@ options:
- Time will always be interpreted as UTC. - Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer - Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h). + C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will start being valid from now. - If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(ownca) provider. - This is only used by the C(ownca) provider.
type: str type: str
default: +0s default: +0s
@@ -470,8 +470,8 @@ options:
- Time will always be interpreted as UTC. - Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer - Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h). + C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will stop being valid 10 years from now. - If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(ownca) provider. - This is only used by the C(ownca) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer. - On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details. Please see U(https://support.apple.com/en-us/HT210176) for more details.
@@ -548,8 +548,8 @@ options:
- Time will always be interpreted as UTC. - Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer - Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h). + C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will start being valid from now. - If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(selfsigned) provider. - This is only used by the C(selfsigned) provider.
type: str type: str
default: +0s default: +0s
@@ -562,8 +562,8 @@ options:
- Time will always be interpreted as UTC. - Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer - Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h). + C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will stop being valid 10 years from now. - If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(selfsigned) provider. - This is only used by the C(selfsigned) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer. - On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details. Please see U(https://support.apple.com/en-us/HT210176) for more details.

View File

@@ -100,7 +100,7 @@ options:
description: description:
- Determines which format the private key is written in. By default, PKCS1 (traditional OpenSSL format) - Determines which format the private key is written in. By default, PKCS1 (traditional OpenSSL format)
is used for all keys which support it. Please note that not every key can be exported in any format. is used for all keys which support it. Please note that not every key can be exported in any format.
- The value C(auto) selects a fromat based on the key format. The value C(auto_ignore) does the same, - The value C(auto) selects a format based on the key format. The value C(auto_ignore) does the same,
but for existing private key files, it will not force a regenerate when its format is not the automatically but for existing private key files, it will not force a regenerate when its format is not the automatically
selected one for generation. selected one for generation.
- Note that if the format for an existing private key mismatches, the key is B(regenerated) by default. - Note that if the format for an existing private key mismatches, the key is B(regenerated) by default.

View File

@@ -0,0 +1,343 @@
# Vendored copy of distutils/version.py from CPython 3.9.5
#
# Implements multiple version numbering conventions for the
# Python Module Distribution Utilities.
#
# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0)
#
"""Provides classes to represent module version numbers (one class for
each style of version numbering). There are currently two such classes
implemented: StrictVersion and LooseVersion.
Every version number class implements the following interface:
* the 'parse' method takes a string and parses it to some internal
representation; if the string is an invalid version number,
'parse' raises a ValueError exception
* the class constructor takes an optional string argument which,
if supplied, is passed to 'parse'
* __str__ reconstructs the string that was passed to 'parse' (or
an equivalent string -- ie. one that will generate an equivalent
version number instance)
* __repr__ generates Python code to recreate the version number instance
* _cmp compares the current instance with either another instance
of the same class or a string (which will be parsed to an instance
of the same class, thus must follow the same rules)
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
try:
RE_FLAGS = re.VERBOSE | re.ASCII
except AttributeError:
RE_FLAGS = re.VERBOSE
class Version:
"""Abstract base class for version numbering classes. Just provides
constructor (__init__) and reproducer (__repr__), because those
seem to be the same for all version numbering classes; and route
rich comparisons to _cmp.
"""
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def __repr__(self):
return "%s ('%s')" % (self.__class__.__name__, str(self))
def __eq__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c == 0
def __lt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c >= 0
# Interface for version-number classes -- must be implemented
# by the following classes (the concrete ones -- Version should
# be treated as an abstract class).
# __init__ (string) - create and take same action as 'parse'
# (string parameter is optional)
# parse (string) - convert a string representation to whatever
# internal representation is appropriate for
# this style of version numbering
# __str__ (self) - convert back to a string; should be very similar
# (if not identical to) the string supplied to parse
# __repr__ (self) - generate Python code to recreate
# the instance
# _cmp (self, other) - compare two version numbers ('other' may
# be an unparsed version string, or another
# instance of your version class)
class StrictVersion(Version):
"""Version numbering for anal retentives and software idealists.
Implements the standard interface for version number classes as
described above. A version number consists of two or three
dot-separated numeric components, with an optional "pre-release" tag
on the end. The pre-release tag consists of the letter 'a' or 'b'
followed by a number. If the numeric components of two version
numbers are equal, then one with a pre-release tag will always
be deemed earlier (lesser) than one without.
The following are valid version numbers (shown in the order that
would be obtained by sorting according to the supplied cmp function):
0.4 0.4.0 (these two are equivalent)
0.4.1
0.5a1
0.5b3
0.5
0.9.6
1.0
1.0.4a3
1.0.4b1
1.0.4
The following are examples of invalid version numbers:
1
2.7.2.2
1.3.a4
1.3pl1
1.3c4
The rationale for this version numbering system will be explained
in the distutils documentation.
"""
version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
RE_FLAGS)
def parse(self, vstring):
match = self.version_re.match(vstring)
if not match:
raise ValueError("invalid version number '%s'" % vstring)
(major, minor, patch, prerelease, prerelease_num) = \
match.group(1, 2, 4, 5, 6)
if patch:
self.version = tuple(map(int, [major, minor, patch]))
else:
self.version = tuple(map(int, [major, minor])) + (0,)
if prerelease:
self.prerelease = (prerelease[0], int(prerelease_num))
else:
self.prerelease = None
def __str__(self):
if self.version[2] == 0:
vstring = '.'.join(map(str, self.version[0:2]))
else:
vstring = '.'.join(map(str, self.version))
if self.prerelease:
vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
return vstring
def _cmp(self, other):
if isinstance(other, str):
other = StrictVersion(other)
elif not isinstance(other, StrictVersion):
return NotImplemented
if self.version != other.version:
# numeric versions don't match
# prerelease stuff doesn't matter
if self.version < other.version:
return -1
else:
return 1
# have to compare prerelease
# case 1: neither has prerelease; they're equal
# case 2: self has prerelease, other doesn't; other is greater
# case 3: self doesn't have prerelease, other does: self is greater
# case 4: both have prerelease: must compare them!
if (not self.prerelease and not other.prerelease):
return 0
elif (self.prerelease and not other.prerelease):
return -1
elif (not self.prerelease and other.prerelease):
return 1
elif (self.prerelease and other.prerelease):
if self.prerelease == other.prerelease:
return 0
elif self.prerelease < other.prerelease:
return -1
else:
return 1
else:
raise AssertionError("never get here")
# end class StrictVersion
# The rules according to Greg Stein:
# 1) a version number has 1 or more numbers separated by a period or by
# sequences of letters. If only periods, then these are compared
# left-to-right to determine an ordering.
# 2) sequences of letters are part of the tuple for comparison and are
# compared lexicographically
# 3) recognize the numeric components may have leading zeroes
#
# The LooseVersion class below implements these rules: a version number
# string is split up into a tuple of integer and string components, and
# comparison is a simple tuple comparison. This means that version
# numbers behave in a predictable and obvious way, but a way that might
# not necessarily be how people *want* version numbers to behave. There
# wouldn't be a problem if people could stick to purely numeric version
# numbers: just split on period and compare the numbers as tuples.
# However, people insist on putting letters into their version numbers;
# the most common purpose seems to be:
# - indicating a "pre-release" version
# ('alpha', 'beta', 'a', 'b', 'pre', 'p')
# - indicating a post-release patch ('p', 'pl', 'patch')
# but of course this can't cover all version number schemes, and there's
# no way to know what a programmer means without asking him.
#
# The problem is what to do with letters (and other non-numeric
# characters) in a version number. The current implementation does the
# obvious and predictable thing: keep them as strings and compare
# lexically within a tuple comparison. This has the desired effect if
# an appended letter sequence implies something "post-release":
# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
#
# However, if letters in a version number imply a pre-release version,
# the "obvious" thing isn't correct. Eg. you would expect that
# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
# implemented here, this just isn't so.
#
# Two possible solutions come to mind. The first is to tie the
# comparison algorithm to a particular set of semantic rules, as has
# been done in the StrictVersion class above. This works great as long
# as everyone can go along with bondage and discipline. Hopefully a
# (large) subset of Python module programmers will agree that the
# particular flavour of bondage and discipline provided by StrictVersion
# provides enough benefit to be worth using, and will submit their
# version numbering scheme to its domination. The free-thinking
# anarchists in the lot will never give in, though, and something needs
# to be done to accommodate them.
#
# Perhaps a "moderately strict" version class could be implemented that
# lets almost anything slide (syntactically), and makes some heuristic
# assumptions about non-digits in version number strings. This could
# sink into special-case-hell, though; if I was as talented and
# idiosyncratic as Larry Wall, I'd go ahead and implement a class that
# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
# just as happy dealing with things like "2g6" and "1.13++". I don't
# think I'm smart enough to do it right though.
#
# In any case, I've coded the test suite for this module (see
# ../test/test_version.py) specifically to fail on things like comparing
# "1.2a2" and "1.2". That's not because the *code* is doing anything
# wrong, it's because the simple, obvious design doesn't match my
# complicated, hairy expectations for real-world version numbers. It
# would be a snap to fix the test suite to say, "Yep, LooseVersion does
# the Right Thing" (ie. the code matches the conception). But I'd rather
# have a conception that matches common notions about version numbers.
class LooseVersion(Version):
"""Version numbering for anarchists and software realists.
Implements the standard interface for version number classes as
described above. A version number consists of a series of numbers,
separated by either periods or strings of letters. When comparing
version numbers, the numeric components will be compared
numerically, and the alphabetic components lexically. The following
are all valid version numbers, in no particular order:
1.5.1
1.5.2b2
161
3.10a
8.02
3.4j
1996.07.12
3.2.pl0
3.1.1.6
2g6
11g
0.960923
2.2beta29
1.13++
5.5.kw
2.0b1pl0
In fact, there is no such thing as an invalid version number under
this scheme; the rules for comparison are simple and predictable,
but may not always give the results you want (for some definition
of "want").
"""
component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def parse(self, vstring):
# I've given up on thinking I can reconstruct the version string
# from the parsed tuple -- so I just store the string here for
# use by __str__
self.vstring = vstring
components = [x for x in self.component_re.split(vstring) if x and x != '.']
for i, obj in enumerate(components):
try:
components[i] = int(obj)
except ValueError:
pass
self.version = components
def __str__(self):
return self.vstring
def __repr__(self):
return "LooseVersion ('%s')" % str(self)
def _cmp(self, other):
if isinstance(other, str):
other = LooseVersion(other)
elif not isinstance(other, LooseVersion):
return NotImplemented
if self.version == other.version:
return 0
if self.version < other.version:
return -1
if self.version > other.version:
return 1
# end class LooseVersion

View File

@@ -14,8 +14,9 @@ import json
import locale import locale
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_bytes
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six import PY3
from ansible_collections.community.crypto.plugins.module_utils.acme.backend_openssl_cli import ( from ansible_collections.community.crypto.plugins.module_utils.acme.backend_openssl_cli import (
OpenSSLCLIBackend, OpenSSLCLIBackend,
@@ -228,9 +229,14 @@ class ACMEClient(object):
resp, info = fetch_url(self.module, url, data=data, headers=headers, method='POST') resp, info = fetch_url(self.module, url, data=data, headers=headers, method='POST')
_assert_fetch_url_success(self.module, resp, info) _assert_fetch_url_success(self.module, resp, info)
result = {} result = {}
try: try:
# In Python 2, reading from a closed response yields a TypeError.
# In Python 3, read() simply returns ''
if PY3 and resp.closed:
raise TypeError
content = resp.read() content = resp.read()
except AttributeError: except (AttributeError, TypeError):
content = info.pop('body', None) content = info.pop('body', None)
if content or not parse_json_result: if content or not parse_json_result:
@@ -284,8 +290,12 @@ class ACMEClient(object):
_assert_fetch_url_success(self.module, resp, info) _assert_fetch_url_success(self.module, resp, info)
try: try:
# In Python 2, reading from a closed response yields a TypeError.
# In Python 3, read() simply returns ''
if PY3 and resp.closed:
raise TypeError
content = resp.read() content = resp.read()
except AttributeError: except (AttributeError, TypeError):
content = info.pop('body', None) content = info.pop('body', None)
# Process result # Process result

View File

@@ -14,7 +14,9 @@ import datetime
import os import os
import sys import sys
from ansible.module_utils.common.text.converters import to_bytes, to_native from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.acme.backends import ( from ansible_collections.community.crypto.plugins.module_utils.acme.backends import (
CryptoBackend, CryptoBackend,
@@ -41,6 +43,10 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp
cryptography_name_to_oid, cryptography_name_to_oid,
) )
from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import (
extract_first_pem,
)
try: try:
import cryptography import cryptography
import cryptography.hazmat.backends import cryptography.hazmat.backends
@@ -53,7 +59,6 @@ try:
import cryptography.hazmat.primitives.serialization import cryptography.hazmat.primitives.serialization
import cryptography.x509 import cryptography.x509
import cryptography.x509.oid import cryptography.x509.oid
from distutils.version import LooseVersion
CRYPTOGRAPHY_VERSION = cryptography.__version__ CRYPTOGRAPHY_VERSION = cryptography.__version__
HAS_CURRENT_CRYPTOGRAPHY = (LooseVersion(CRYPTOGRAPHY_VERSION) >= LooseVersion('1.5')) HAS_CURRENT_CRYPTOGRAPHY = (LooseVersion(CRYPTOGRAPHY_VERSION) >= LooseVersion('1.5'))
if HAS_CURRENT_CRYPTOGRAPHY: if HAS_CURRENT_CRYPTOGRAPHY:
@@ -357,6 +362,9 @@ class CryptographyBackend(CryptoBackend):
if cert_content is None: if cert_content is None:
return -1 return -1
# Make sure we have at most one PEM. Otherwise cryptography 36.0.0 will barf.
cert_content = to_bytes(extract_first_pem(to_text(cert_content)) or '')
try: try:
cert = cryptography.x509.load_pem_x509_certificate(cert_content, _cryptography_backend) cert = cryptography.x509.load_pem_x509_certificate(cert_content, _cryptography_backend)
except Exception as e: except Exception as e:

View File

@@ -7,8 +7,8 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
from ansible.module_utils.six import binary_type
from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.six import binary_type, PY3
def format_error_problem(problem, subproblem_prefix=''): def format_error_problem(problem, subproblem_prefix=''):
@@ -52,8 +52,12 @@ class ACMEProtocolException(ModuleFailException):
# Try to get hold of content, if response is given and content is not provided # Try to get hold of content, if response is given and content is not provided
if content is None and content_json is None and response is not None: if content is None and content_json is None and response is not None:
try: try:
# In Python 2, reading from a closed response yields a TypeError.
# In Python 3, read() simply returns ''
if PY3 and response.closed:
raise TypeError
content = response.read() content = response.read()
except AttributeError: except (AttributeError, TypeError):
content = info.pop('body', None) content = info.pop('body', None)
# Make sure that content_json is None or a dictionary # Make sure that content_json is None or a dictionary

View File

@@ -2,6 +2,8 @@
# 2.0, and the BSD License. See the LICENSE file at # 2.0, and the BSD License. See the LICENSE file at
# https://github.com/pyca/cryptography/blob/master/LICENSE for complete details. # https://github.com/pyca/cryptography/blob/master/LICENSE for complete details.
# #
# The Apache 2.0 license has been included as Apache-2.0.txt in this collection.
#
# Adapted from cryptography's hazmat/backends/openssl/decode_asn1.py # Adapted from cryptography's hazmat/backends/openssl/decode_asn1.py
# #
# Copyright (c) 2015, 2016 Paul Kehrer (@reaperhulk) # Copyright (c) 2015, 2016 Paul Kehrer (@reaperhulk)
@@ -20,6 +22,10 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
# WARNING: this function no longer works with cryptography 35.0.0 and newer!
# It must **ONLY** be used in compatibility code for older
# cryptography versions!
def obj2txt(openssl_lib, openssl_ffi, obj): def obj2txt(openssl_lib, openssl_ffi, obj):
# Set to 80 on the recommendation of # Set to 80 on the recommendation of
# https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values

View File

@@ -5,7 +5,7 @@
# In case the following data structure has any copyrightable content, note that it is licensed as follows: # In case the following data structure has any copyrightable content, note that it is licensed as follows:
# Copyright (c) the OpenSSL contributors # Copyright (c) the OpenSSL contributors
# Licensed under the Apache License 2.0 # Licensed under the Apache License 2.0
# https://github.com/openssl/openssl/blob/master/LICENSE # https://github.com/openssl/openssl/blob/master/LICENSE.txt or Apache-2.0.txt
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type

View File

@@ -20,13 +20,13 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
from distutils.version import LooseVersion from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
try: try:
import OpenSSL # noqa import OpenSSL # noqa
from OpenSSL import crypto # noqa from OpenSSL import crypto # noqa
HAS_PYOPENSSL = True HAS_PYOPENSSL = True
except ImportError: except (ImportError, AttributeError):
# Error handled in the calling module. # Error handled in the calling module.
HAS_PYOPENSSL = False HAS_PYOPENSSL = False

View File

@@ -26,15 +26,41 @@ import re
from ansible.module_utils.common.text.converters import to_text, to_bytes from ansible.module_utils.common.text.converters import to_text, to_bytes
from ._asn1 import serialize_asn1_string_as_der from ._asn1 import serialize_asn1_string_as_der
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
try: try:
import cryptography import cryptography
from cryptography import x509 from cryptography import x509
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
import ipaddress import ipaddress
except ImportError: except ImportError:
# Error handled in the calling module. # Error handled in the calling module.
pass pass
try:
import cryptography.hazmat.primitives.asymmetric.rsa
except ImportError:
pass
try:
import cryptography.hazmat.primitives.asymmetric.ec
except ImportError:
pass
try:
import cryptography.hazmat.primitives.asymmetric.dsa
except ImportError:
pass
try:
import cryptography.hazmat.primitives.asymmetric.ed25519
except ImportError:
pass
try:
import cryptography.hazmat.primitives.asymmetric.ed448
except ImportError:
pass
try: try:
# This is a separate try/except since this is only present in cryptography 2.5 or newer # This is a separate try/except since this is only present in cryptography 2.5 or newer
from cryptography.hazmat.primitives.serialization.pkcs12 import ( from cryptography.hazmat.primitives.serialization.pkcs12 import (
@@ -44,9 +70,23 @@ except ImportError:
# Error handled in the calling module. # Error handled in the calling module.
_load_key_and_certificates = None _load_key_and_certificates = None
try:
# This is a separate try/except since this is only present in cryptography 36.0.0 or newer
from cryptography.hazmat.primitives.serialization.pkcs12 import (
load_pkcs12 as _load_pkcs12,
)
except ImportError:
# Error handled in the calling module.
_load_pkcs12 = None
from .basic import ( from .basic import (
CRYPTOGRAPHY_HAS_DSA_SIGN,
CRYPTOGRAPHY_HAS_EC_SIGN,
CRYPTOGRAPHY_HAS_ED25519, CRYPTOGRAPHY_HAS_ED25519,
CRYPTOGRAPHY_HAS_ED25519_SIGN,
CRYPTOGRAPHY_HAS_ED448, CRYPTOGRAPHY_HAS_ED448,
CRYPTOGRAPHY_HAS_ED448_SIGN,
CRYPTOGRAPHY_HAS_RSA_SIGN,
OpenSSLObjectError, OpenSSLObjectError,
) )
@@ -64,60 +104,114 @@ DOTTED_OID = re.compile(r'^\d+(?:\.\d+)+$')
def cryptography_get_extensions_from_cert(cert): def cryptography_get_extensions_from_cert(cert):
# Since cryptography won't give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
result = dict() result = dict()
backend = cert._backend try:
x509_obj = cert._x509 # Since cryptography won't give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
# which has no _lib attribute. In that case, revert to the old approach.
backend._lib
except AttributeError:
backend = cert._backend
x509_obj = cert._x509
# With cryptography 35.0.0, we can no longer use obj2txt. Unfortunately it still does
# not allow to get the raw value of an extension, so we have to use this ugly hack:
exts = list(cert.extensions)
for i in range(backend._lib.X509_get_ext_count(x509_obj)):
ext = backend._lib.X509_get_ext(x509_obj, i)
if ext == backend._ffi.NULL:
continue
crit = backend._lib.X509_EXTENSION_get_critical(ext)
data = backend._lib.X509_EXTENSION_get_data(ext)
backend.openssl_assert(data != backend._ffi.NULL)
der = backend._ffi.buffer(data.data, data.length)[:]
entry = dict(
critical=(crit == 1),
value=base64.b64encode(der),
)
try:
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
except AttributeError:
oid = exts[i].oid.dotted_string
result[oid] = entry
except Exception:
# In case the above method breaks, we likely have cryptography 36.0.0 or newer.
# Use it's public_bytes() feature in that case. We will later switch this around
# so that this code will be the default, but for now this will act as a fallback
# since it will re-serialize de-serialized data, which can be different (if the
# original data was not canonicalized) from what was contained in the certificate.
for ext in cert.extensions:
result[ext.oid.dotted_string] = dict(
critical=ext.critical,
value=base64.b64encode(ext.value.public_bytes()),
)
for i in range(backend._lib.X509_get_ext_count(x509_obj)):
ext = backend._lib.X509_get_ext(x509_obj, i)
if ext == backend._ffi.NULL:
continue
crit = backend._lib.X509_EXTENSION_get_critical(ext)
data = backend._lib.X509_EXTENSION_get_data(ext)
backend.openssl_assert(data != backend._ffi.NULL)
der = backend._ffi.buffer(data.data, data.length)[:]
entry = dict(
critical=(crit == 1),
value=base64.b64encode(der),
)
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
result[oid] = entry
return result return result
def cryptography_get_extensions_from_csr(csr): def cryptography_get_extensions_from_csr(csr):
# Since cryptography won't give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
result = dict() result = dict()
backend = csr._backend try:
# Since cryptography won't give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
# which has no _lib attribute. In that case, revert to the old approach.
backend._lib
except AttributeError:
backend = csr._backend
extensions = backend._lib.X509_REQ_get_extensions(csr._x509_req) extensions = backend._lib.X509_REQ_get_extensions(csr._x509_req)
extensions = backend._ffi.gc( extensions = backend._ffi.gc(
extensions, extensions,
lambda ext: backend._lib.sk_X509_EXTENSION_pop_free( lambda ext: backend._lib.sk_X509_EXTENSION_pop_free(
ext, ext,
backend._ffi.addressof(backend._lib._original_lib, "X509_EXTENSION_free") backend._ffi.addressof(backend._lib._original_lib, "X509_EXTENSION_free")
)
) )
)
for i in range(backend._lib.sk_X509_EXTENSION_num(extensions)): # With cryptography 35.0.0, we can no longer use obj2txt. Unfortunately it still does
ext = backend._lib.sk_X509_EXTENSION_value(extensions, i) # not allow to get the raw value of an extension, so we have to use this ugly hack:
if ext == backend._ffi.NULL: exts = list(csr.extensions)
continue
crit = backend._lib.X509_EXTENSION_get_critical(ext) for i in range(backend._lib.sk_X509_EXTENSION_num(extensions)):
data = backend._lib.X509_EXTENSION_get_data(ext) ext = backend._lib.sk_X509_EXTENSION_value(extensions, i)
backend.openssl_assert(data != backend._ffi.NULL) if ext == backend._ffi.NULL:
der = backend._ffi.buffer(data.data, data.length)[:] continue
entry = dict( crit = backend._lib.X509_EXTENSION_get_critical(ext)
critical=(crit == 1), data = backend._lib.X509_EXTENSION_get_data(ext)
value=base64.b64encode(der), backend.openssl_assert(data != backend._ffi.NULL)
) der = backend._ffi.buffer(data.data, data.length)[:]
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext)) entry = dict(
result[oid] = entry critical=(crit == 1),
value=base64.b64encode(der),
)
try:
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
except AttributeError:
oid = exts[i].oid.dotted_string
result[oid] = entry
except Exception:
# In case the above method breaks, we likely have cryptography 36.0.0 or newer.
# Use it's public_bytes() feature in that case. We will later switch this around
# so that this code will be the default, but for now this will act as a fallback
# since it will re-serialize de-serialized data, which can be different (if the
# original data was not canonicalized) from what was contained in the CSR.
for ext in csr.extensions:
result[ext.oid.dotted_string] = dict(
critical=ext.critical,
value=base64.b64encode(ext.value.public_bytes()),
)
return result return result
@@ -280,11 +374,11 @@ def _dn_escape_value(value):
''' '''
Escape Distinguished Name's attribute value. Escape Distinguished Name's attribute value.
''' '''
value = value.replace('\\', '\\\\') value = value.replace(u'\\', u'\\\\')
for ch in [',', '#', '+', '<', '>', ';', '"', '=', '/']: for ch in [u',', u'#', u'+', u'<', u'>', u';', u'"', u'=', u'/']:
value = value.replace(ch, '\\%s' % ch) value = value.replace(ch, u'\\%s' % ch)
if value.startswith(' '): if value.startswith(u' '):
value = r'\ ' + value[1:] value = u'\\ ' + value[1:]
return value return value
@@ -294,24 +388,24 @@ def cryptography_decode_name(name):
Raises an OpenSSLObjectError if the name is not supported. Raises an OpenSSLObjectError if the name is not supported.
''' '''
if isinstance(name, x509.DNSName): if isinstance(name, x509.DNSName):
return 'DNS:{0}'.format(name.value) return u'DNS:{0}'.format(name.value)
if isinstance(name, x509.IPAddress): if isinstance(name, x509.IPAddress):
if isinstance(name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)): if isinstance(name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)):
return 'IP:{0}/{1}'.format(name.value.network_address.compressed, name.value.prefixlen) return u'IP:{0}/{1}'.format(name.value.network_address.compressed, name.value.prefixlen)
return 'IP:{0}'.format(name.value.compressed) return u'IP:{0}'.format(name.value.compressed)
if isinstance(name, x509.RFC822Name): if isinstance(name, x509.RFC822Name):
return 'email:{0}'.format(name.value) return u'email:{0}'.format(name.value)
if isinstance(name, x509.UniformResourceIdentifier): if isinstance(name, x509.UniformResourceIdentifier):
return 'URI:{0}'.format(name.value) return u'URI:{0}'.format(name.value)
if isinstance(name, x509.DirectoryName): if isinstance(name, x509.DirectoryName):
return 'dirName:' + ''.join([ return u'dirName:' + u''.join([
'/{0}={1}'.format(cryptography_oid_to_name(attribute.oid, short=True), _dn_escape_value(attribute.value)) u'/{0}={1}'.format(to_text(cryptography_oid_to_name(attribute.oid, short=True)), _dn_escape_value(attribute.value))
for attribute in name.value for attribute in name.value
]) ])
if isinstance(name, x509.RegisteredID): if isinstance(name, x509.RegisteredID):
return 'RID:{0}'.format(name.value.dotted_string) return u'RID:{0}'.format(name.value.dotted_string)
if isinstance(name, x509.OtherName): if isinstance(name, x509.OtherName):
return 'otherName:{0};{1}'.format(name.type_id.dotted_string, _get_hex(name.value)) return u'otherName:{0};{1}'.format(name.type_id.dotted_string, _get_hex(name.value))
raise OpenSSLObjectError('Cannot decode name "{0}"'.format(name)) raise OpenSSLObjectError('Cannot decode name "{0}"'.format(name))
@@ -442,17 +536,111 @@ def cryptography_serial_number_of_cert(cert):
def parse_pkcs12(pkcs12_bytes, passphrase=None): def parse_pkcs12(pkcs12_bytes, passphrase=None):
'''Returns a tuple (private_key, certificate, additional_certificates, friendly_name). '''Returns a tuple (private_key, certificate, additional_certificates, friendly_name).
''' '''
if _load_key_and_certificates is None: if _load_pkcs12 is None and _load_key_and_certificates is None:
raise ValueError('load_key_and_certificates() not present in the current cryptography version') raise ValueError('neither load_pkcs12() nor load_key_and_certificates() present in the current cryptography version')
private_key, certificate, additional_certificates = _load_key_and_certificates(
pkcs12_bytes, to_bytes(passphrase) if passphrase is not None else None) if passphrase is not None:
passphrase = to_bytes(passphrase)
# Main code for cryptography 36.0.0 and forward
if _load_pkcs12 is not None:
return _parse_pkcs12_36_0_0(pkcs12_bytes, passphrase)
if LooseVersion(cryptography.__version__) >= LooseVersion('35.0'):
return _parse_pkcs12_35_0_0(pkcs12_bytes, passphrase)
return _parse_pkcs12_legacy(pkcs12_bytes, passphrase)
def _parse_pkcs12_36_0_0(pkcs12_bytes, passphrase=None):
# Requires cryptography 36.0.0 or newer
pkcs12 = _load_pkcs12(pkcs12_bytes, passphrase)
additional_certificates = [cert.certificate for cert in pkcs12.additional_certs]
private_key = pkcs12.key
certificate = None
friendly_name = None
if pkcs12.cert:
certificate = pkcs12.cert.certificate
friendly_name = pkcs12.cert.friendly_name
return private_key, certificate, additional_certificates, friendly_name
def _parse_pkcs12_35_0_0(pkcs12_bytes, passphrase=None):
# Backwards compatibility code for cryptography 35.x
private_key, certificate, additional_certificates = _load_key_and_certificates(pkcs12_bytes, passphrase)
friendly_name = None friendly_name = None
if certificate: if certificate:
# See https://github.com/pyca/cryptography/issues/5760#issuecomment-842687238 # See https://github.com/pyca/cryptography/issues/5760#issuecomment-842687238
maybe_name = certificate._backend._lib.X509_alias_get0( backend = default_backend()
certificate._x509, certificate._backend._ffi.NULL)
if maybe_name != certificate._backend._ffi.NULL: # This code basically does what load_key_and_certificates() does, but without error-checking.
friendly_name = certificate._backend._ffi.string(maybe_name) # Since load_key_and_certificates succeeded, it should not fail.
pkcs12 = backend._ffi.gc(
backend._lib.d2i_PKCS12_bio(backend._bytes_to_bio(pkcs12_bytes).bio, backend._ffi.NULL),
backend._lib.PKCS12_free)
certificate_x509_ptr = backend._ffi.new("X509 **")
with backend._zeroed_null_terminated_buf(to_bytes(passphrase) if passphrase is not None else None) as passphrase_buffer:
backend._lib.PKCS12_parse(
pkcs12,
passphrase_buffer,
backend._ffi.new("EVP_PKEY **"),
certificate_x509_ptr,
backend._ffi.new("Cryptography_STACK_OF_X509 **"))
if certificate_x509_ptr[0] != backend._ffi.NULL:
maybe_name = backend._lib.X509_alias_get0(certificate_x509_ptr[0], backend._ffi.NULL)
if maybe_name != backend._ffi.NULL:
friendly_name = backend._ffi.string(maybe_name)
return private_key, certificate, additional_certificates, friendly_name return private_key, certificate, additional_certificates, friendly_name
def _parse_pkcs12_legacy(pkcs12_bytes, passphrase=None):
# Backwards compatibility code for cryptography < 35.0.0
private_key, certificate, additional_certificates = _load_key_and_certificates(pkcs12_bytes, passphrase)
friendly_name = None
if certificate:
# See https://github.com/pyca/cryptography/issues/5760#issuecomment-842687238
backend = certificate._backend
maybe_name = backend._lib.X509_alias_get0(certificate._x509, backend._ffi.NULL)
if maybe_name != backend._ffi.NULL:
friendly_name = backend._ffi.string(maybe_name)
return private_key, certificate, additional_certificates, friendly_name
def cryptography_verify_signature(signature, data, hash_algorithm, signer_public_key):
'''
Check whether the given signature of the given data was signed by the given public key object.
'''
try:
if CRYPTOGRAPHY_HAS_RSA_SIGN and isinstance(signer_public_key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey):
signer_public_key.verify(signature, data, padding.PKCS1v15(), hash_algorithm)
return True
if CRYPTOGRAPHY_HAS_EC_SIGN and isinstance(signer_public_key, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey):
signer_public_key.verify(signature, data, cryptography.hazmat.primitives.asymmetric.ec.ECDSA(hash_algorithm))
return True
if CRYPTOGRAPHY_HAS_DSA_SIGN and isinstance(signer_public_key, cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey):
signer_public_key.verify(signature, data, hash_algorithm)
return True
if CRYPTOGRAPHY_HAS_ED25519_SIGN and isinstance(signer_public_key, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey):
signer_public_key.verify(signature, data)
return True
if CRYPTOGRAPHY_HAS_ED448_SIGN and isinstance(signer_public_key, cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey):
signer_public_key.verify(signature, data)
return True
raise OpenSSLObjectError(u'Unsupported public key type {0}'.format(type(signer_public_key)))
except InvalidSignature:
return False
def cryptography_verify_certificate_signature(certificate, signer_public_key):
'''
Check whether the given X509 certificate object was signed by the given public key object.
'''
return cryptography_verify_signature(
certificate.signature,
certificate.tbs_certificate_bytes,
certificate.signature_hash_algorithm,
signer_public_key
)

View File

@@ -53,9 +53,18 @@ def quick_is_not_prime(n):
that we couldn't detect quickly whether it is not prime. that we couldn't detect quickly whether it is not prime.
''' '''
if n <= 2: if n <= 2:
return True return n < 2
# The constant in the next line is the product of all primes < 200 # The constant in the next line is the product of all primes < 200
if simple_gcd(n, 7799922041683461553249199106329813876687996789903550945093032474868511536164700810) > 1: prime_product = 7799922041683461553249199106329813876687996789903550945093032474868511536164700810
gcd = simple_gcd(n, prime_product)
if gcd > 1:
if n < 200 and gcd == n:
# Explicitly check for all primes < 200
return n not in (
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199,
)
return True return True
# TODO: maybe do some iterations of Miller-Rabin to increase confidence # TODO: maybe do some iterations of Miller-Rabin to increase confidence
# (https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test) # (https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test)

View File

@@ -11,11 +11,11 @@ __metaclass__ = type
import abc import abc
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
@@ -45,7 +45,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -13,6 +13,10 @@ import datetime
from ansible.module_utils.common.text.converters import to_native, to_bytes, to_text from ansible.module_utils.common.text.converters import to_native, to_bytes, to_text
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
OpenSSLObjectError,
)
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
parse_name_field, parse_name_field,
get_relative_time_option, get_relative_time_option,
@@ -37,7 +41,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac
try: try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
except ImportError: except (ImportError, AttributeError):
pass pass
try: try:
@@ -485,8 +489,11 @@ class AssertOnlyCertificateBackendPyOpenSSL(AssertOnlyCertificateBackend):
def _validate_privatekey(self): def _validate_privatekey(self):
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD)
ctx.use_privatekey(self.privatekey) try:
ctx.use_certificate(self.existing_certificate) ctx.use_privatekey(self.privatekey)
ctx.use_certificate(self.existing_certificate)
except OpenSSL.SSL.Error as exc:
raise OpenSSLObjectError('Unexpected error while trying to validate private key with certificate: %s' % exc)
try: try:
ctx.check_privatekey() ctx.check_privatekey()
return True return True

View File

@@ -15,12 +15,12 @@ import datetime
import re import re
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
load_certificate, load_certificate,
get_fingerprint_of_bytes, get_fingerprint_of_bytes,
@@ -59,7 +59,7 @@ try:
# OpenSSL 1.0.x or older # OpenSSL 1.0.x or older
OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24" OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24"
OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05" OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05"
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -10,11 +10,12 @@ __metaclass__ = type
import os import os
from distutils.version import LooseVersion
from random import randrange from random import randrange
from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
OpenSSLBadPassphraseError, OpenSSLBadPassphraseError,
) )
@@ -27,8 +28,10 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
) )
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
cryptography_compare_public_keys,
cryptography_key_needs_digest_for_signing, cryptography_key_needs_digest_for_signing,
cryptography_serial_number_of_cert, cryptography_serial_number_of_cert,
cryptography_verify_certificate_signature,
) )
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import (
@@ -40,7 +43,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac
try: try:
from OpenSSL import crypto from OpenSSL import crypto
except ImportError: except (ImportError, AttributeError):
pass pass
try: try:
@@ -106,6 +109,9 @@ class OwnCACertificateBackendCryptography(CertificateBackend):
except OpenSSLBadPassphraseError as exc: except OpenSSLBadPassphraseError as exc:
module.fail_json(msg=str(exc)) module.fail_json(msg=str(exc))
if not cryptography_compare_public_keys(self.ca_cert.public_key(), self.ca_private_key.public_key()):
raise CertificateError('The CA private key does not belong to the CA certificate')
if cryptography_key_needs_digest_for_signing(self.ca_private_key): if cryptography_key_needs_digest_for_signing(self.ca_private_key):
if self.digest is None: if self.digest is None:
raise CertificateError( raise CertificateError(
@@ -172,6 +178,16 @@ class OwnCACertificateBackendCryptography(CertificateBackend):
if super(OwnCACertificateBackendCryptography, self).needs_regeneration(): if super(OwnCACertificateBackendCryptography, self).needs_regeneration():
return True return True
self._ensure_existing_certificate_loaded()
# Check whether certificate is signed by CA certificate
if not cryptography_verify_certificate_signature(self.existing_certificate, self.ca_cert.public_key()):
return True
# Check subject
if self.ca_cert.subject != self.existing_certificate.issuer:
return True
# Check AuthorityKeyIdentifier # Check AuthorityKeyIdentifier
if self.create_authority_key_identifier: if self.create_authority_key_identifier:
try: try:
@@ -184,7 +200,6 @@ class OwnCACertificateBackendCryptography(CertificateBackend):
except cryptography.x509.ExtensionNotFound: except cryptography.x509.ExtensionNotFound:
expected_ext = x509.AuthorityKeyIdentifier.from_issuer_public_key(self.ca_cert.public_key()) expected_ext = x509.AuthorityKeyIdentifier.from_issuer_public_key(self.ca_cert.public_key())
self._ensure_existing_certificate_loaded()
try: try:
ext = self.existing_certificate.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier) ext = self.existing_certificate.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier)
if ext.value != expected_ext: if ext.value != expected_ext:
@@ -296,6 +311,18 @@ class OwnCACertificateBackendPyOpenSSL(CertificateBackend):
"""Return bytes for self.cert.""" """Return bytes for self.cert."""
return crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert) return crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert)
def needs_regeneration(self):
if super(OwnCACertificateBackendPyOpenSSL, self).needs_regeneration():
return True
self._ensure_existing_certificate_loaded()
# Check subject
if self.ca_cert.get_subject() != self.existing_certificate.get_issuer():
return True
return False
def dump(self, include_certificate): def dump(self, include_certificate):
result = super(OwnCACertificateBackendPyOpenSSL, self).dump(include_certificate) result = super(OwnCACertificateBackendPyOpenSSL, self).dump(include_certificate)
result.update({ result.update({

View File

@@ -22,6 +22,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
cryptography_key_needs_digest_for_signing, cryptography_key_needs_digest_for_signing,
cryptography_serial_number_of_cert, cryptography_serial_number_of_cert,
cryptography_verify_certificate_signature,
) )
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import (
@@ -32,7 +33,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac
try: try:
from OpenSSL import crypto from OpenSSL import crypto
except ImportError: except (ImportError, AttributeError):
pass pass
try: try:
@@ -134,6 +135,18 @@ class SelfSignedCertificateBackendCryptography(CertificateBackend):
"""Return bytes for self.cert.""" """Return bytes for self.cert."""
return self.cert.public_bytes(Encoding.PEM) return self.cert.public_bytes(Encoding.PEM)
def needs_regeneration(self):
if super(SelfSignedCertificateBackendCryptography, self).needs_regeneration():
return True
self._ensure_existing_certificate_loaded()
# Check whether certificate is signed by private key
if not cryptography_verify_certificate_signature(self.existing_certificate, self.privatekey.public_key()):
return True
return False
def dump(self, include_certificate): def dump(self, include_certificate):
result = super(SelfSignedCertificateBackendCryptography, self).dump(include_certificate) result = super(SelfSignedCertificateBackendCryptography, self).dump(include_certificate)

View File

@@ -9,10 +9,10 @@ __metaclass__ = type
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
cryptography_oid_to_name, cryptography_oid_to_name,
) )

View File

@@ -12,12 +12,12 @@ import abc
import binascii import binascii
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
OpenSSLObjectError, OpenSSLObjectError,
OpenSSLBadPassphraseError, OpenSSLBadPassphraseError,
@@ -63,7 +63,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:
@@ -452,8 +452,12 @@ def parse_crl_distribution_points(module, crl_distribution_points):
reasons=None, reasons=None,
) )
if parse_crl_distribution_point['full_name'] is not None: if parse_crl_distribution_point['full_name'] is not None:
if not parse_crl_distribution_point['full_name']:
raise OpenSSLObjectError('full_name must not be empty')
params['full_name'] = [cryptography_get_name(name, 'full name') for name in parse_crl_distribution_point['full_name']] params['full_name'] = [cryptography_get_name(name, 'full name') for name in parse_crl_distribution_point['full_name']]
if parse_crl_distribution_point['relative_name'] is not None: if parse_crl_distribution_point['relative_name'] is not None:
if not parse_crl_distribution_point['relative_name']:
raise OpenSSLObjectError('relative_name must not be empty')
try: try:
params['relative_name'] = cryptography_parse_relative_distinguished_name(parse_crl_distribution_point['relative_name']) params['relative_name'] = cryptography_parse_relative_distinguished_name(parse_crl_distribution_point['relative_name'])
except Exception: except Exception:
@@ -462,6 +466,8 @@ def parse_crl_distribution_points(module, crl_distribution_points):
raise OpenSSLObjectError('Cannot specify relative_name for cryptography < 1.6') raise OpenSSLObjectError('Cannot specify relative_name for cryptography < 1.6')
raise raise
if parse_crl_distribution_point['crl_issuer'] is not None: if parse_crl_distribution_point['crl_issuer'] is not None:
if not parse_crl_distribution_point['crl_issuer']:
raise OpenSSLObjectError('crl_issuer must not be empty')
params['crl_issuer'] = [cryptography_get_name(name, 'CRL issuer') for name in parse_crl_distribution_point['crl_issuer']] params['crl_issuer'] = [cryptography_get_name(name, 'CRL issuer') for name in parse_crl_distribution_point['crl_issuer']]
if parse_crl_distribution_point['reasons'] is not None: if parse_crl_distribution_point['reasons'] is not None:
reasons = [] reasons = []
@@ -469,7 +475,7 @@ def parse_crl_distribution_points(module, crl_distribution_points):
reasons.append(REVOCATION_REASON_MAP[reason]) reasons.append(REVOCATION_REASON_MAP[reason])
params['reasons'] = frozenset(reasons) params['reasons'] = frozenset(reasons)
result.append(cryptography.x509.DistributionPoint(**params)) result.append(cryptography.x509.DistributionPoint(**params))
except OpenSSLObjectError as e: except (OpenSSLObjectError, ValueError) as e:
raise OpenSSLObjectError('Error while parsing CRL distribution point #{index}: {error}'.format(index=index, error=e)) raise OpenSSLObjectError('Error while parsing CRL distribution point #{index}: {error}'.format(index=index, error=e))
return result return result
@@ -528,8 +534,8 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
if self.name_constraints_permitted or self.name_constraints_excluded: if self.name_constraints_permitted or self.name_constraints_excluded:
try: try:
csr = csr.add_extension(cryptography.x509.NameConstraints( csr = csr.add_extension(cryptography.x509.NameConstraints(
[cryptography_get_name(name, 'name constraints permitted') for name in self.name_constraints_permitted], [cryptography_get_name(name, 'name constraints permitted') for name in self.name_constraints_permitted] or None,
[cryptography_get_name(name, 'name constraints excluded') for name in self.name_constraints_excluded], [cryptography_get_name(name, 'name constraints excluded') for name in self.name_constraints_excluded] or None,
), critical=self.name_constraints_critical) ), critical=self.name_constraints_critical)
except TypeError as e: except TypeError as e:
raise OpenSSLObjectError('Error while parsing name constraint: {0}'.format(e)) raise OpenSSLObjectError('Error while parsing name constraint: {0}'.format(e))
@@ -678,8 +684,8 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
def _check_nameConstraints(extensions): def _check_nameConstraints(extensions):
current_nc_ext = _find_extension(extensions, cryptography.x509.NameConstraints) current_nc_ext = _find_extension(extensions, cryptography.x509.NameConstraints)
current_nc_perm = [to_text(altname) for altname in current_nc_ext.value.permitted_subtrees] if current_nc_ext else [] current_nc_perm = [to_text(altname) for altname in current_nc_ext.value.permitted_subtrees or []] if current_nc_ext else []
current_nc_excl = [to_text(altname) for altname in current_nc_ext.value.excluded_subtrees] if current_nc_ext else [] current_nc_excl = [to_text(altname) for altname in current_nc_ext.value.excluded_subtrees or []] if current_nc_ext else []
nc_perm = [to_text(cryptography_get_name(altname, 'name constraints permitted')) for altname in self.name_constraints_permitted] nc_perm = [to_text(cryptography_get_name(altname, 'name constraints permitted')) for altname in self.name_constraints_permitted]
nc_excl = [to_text(cryptography_get_name(altname, 'name constraints excluded')) for altname in self.name_constraints_excluded] nc_excl = [to_text(cryptography_get_name(altname, 'name constraints excluded')) for altname in self.name_constraints_excluded]
if set(nc_perm) != set(current_nc_perm) or set(nc_excl) != set(current_nc_excl): if set(nc_perm) != set(current_nc_perm) or set(nc_excl) != set(current_nc_excl):
@@ -851,7 +857,8 @@ def get_csr_argument_spec():
'aa_compromise', 'aa_compromise',
]), ]),
), ),
mutually_exclusive=[('full_name', 'relative_name')] mutually_exclusive=[('full_name', 'relative_name')],
required_one_of=[('full_name', 'relative_name', 'crl_issuer')],
), ),
select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']),
), ),

View File

@@ -13,12 +13,12 @@ import abc
import binascii import binascii
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
load_certificate_request, load_certificate_request,
get_fingerprint_of_bytes, get_fingerprint_of_bytes,
@@ -57,7 +57,7 @@ try:
# OpenSSL 1.0.x or older # OpenSSL 1.0.x or older
OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24" OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24"
OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05" OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05"
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -12,12 +12,12 @@ import abc
import base64 import base64
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
CRYPTOGRAPHY_HAS_X25519, CRYPTOGRAPHY_HAS_X25519,
CRYPTOGRAPHY_HAS_X25519_FULL, CRYPTOGRAPHY_HAS_X25519_FULL,
@@ -54,7 +54,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -12,12 +12,12 @@ __metaclass__ = type
import abc import abc
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_bytes from ansible.module_utils.common.text.converters import to_native, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
CRYPTOGRAPHY_HAS_ED25519, CRYPTOGRAPHY_HAS_ED25519,
CRYPTOGRAPHY_HAS_ED448, CRYPTOGRAPHY_HAS_ED448,
@@ -49,7 +49,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:
@@ -119,7 +119,10 @@ def _check_dsa_consistency(key_public_data, key_private_data):
def _is_cryptography_key_consistent(key, key_public_data, key_private_data): def _is_cryptography_key_consistent(key, key_public_data, key_private_data):
if isinstance(key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey): if isinstance(key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey):
return bool(key._backend._lib.RSA_check_key(key._rsa_cdata)) # key._backend was removed in cryptography 42.0.0
backend = getattr(key, '_backend', None)
if backend is not None:
return bool(backend._lib.RSA_check_key(key._rsa_cdata))
if isinstance(key, cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey): if isinstance(key, cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey):
result = _check_dsa_consistency(key_public_data, key_private_data) result = _check_dsa_consistency(key_public_data, key_private_data)
if result is not None: if result is not None:

View File

@@ -10,12 +10,12 @@ __metaclass__ = type
import abc import abc
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
CRYPTOGRAPHY_HAS_X25519, CRYPTOGRAPHY_HAS_X25519,
CRYPTOGRAPHY_HAS_X448, CRYPTOGRAPHY_HAS_X448,
@@ -38,7 +38,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:
@@ -215,7 +215,7 @@ class PublicKeyInfoRetrieval(object):
try: try:
self.key = load_publickey(content=self.content, backend=self.backend) self.key = load_publickey(content=self.content, backend=self.backend)
except OpenSSLObjectError as e: except OpenSSLObjectError as e:
raise PublicKeyParseError(to_native(e)) raise PublicKeyParseError(to_native(e), {})
pk = self._get_public_key(binary=True) pk = self._get_public_key(binary=True)
result['fingerprints'] = get_fingerprint_of_bytes( result['fingerprints'] = get_fingerprint_of_bytes(

View File

@@ -72,3 +72,13 @@ def split_pem_list(text, keep_inbetween=False):
result.append(''.join(current)) result.append(''.join(current))
current = [] if keep_inbetween else None current = [] if keep_inbetween else None
return result return result
def extract_first_pem(text):
'''
Given one PEM or multiple concatenated PEM objects, return only the first one, or None if there is none.
'''
all_pems = split_pem_list(text)
if not all_pems:
return None
return all_pems[0]

View File

@@ -21,13 +21,15 @@ __metaclass__ = type
import base64 import base64
from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress
from ._objects import OID_LOOKUP
try: try:
import OpenSSL import OpenSSL
except ImportError: except (ImportError, AttributeError):
# Error handled in the calling module. # Error handled in the calling module.
pass pass
@@ -87,18 +89,25 @@ def pyopenssl_get_extensions_from_cert(cert):
critical=bool(ext.get_critical()), critical=bool(ext.get_critical()),
value=base64.b64encode(ext.get_data()), value=base64.b64encode(ext.get_data()),
) )
oid = obj2txt( try:
OpenSSL._util.lib, oid = obj2txt(
OpenSSL._util.ffi, OpenSSL._util.lib,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension) OpenSSL._util.ffi,
) OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
# This could also be done a bit simpler: )
# # This could also be done a bit simpler:
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid)) #
# # oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
# Unfortunately this gives the wrong result in case the linked OpenSSL #
# doesn't know the OID. That's why we have to get the OID dotted string # Unfortunately this gives the wrong result in case the linked OpenSSL
# similarly to how cryptography does it. # doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
except AttributeError:
# When PyOpenSSL is used with cryptography >= 35.0.0, obj2txt cannot be used.
# We try to figure out the OID with our internal lookup table, and if we fail,
# we use the short name OpenSSL returns.
oid = to_native(ext.get_short_name())
oid = OID_LOOKUP.get(oid, oid)
result[oid] = entry result[oid] = entry
return result return result
@@ -113,18 +122,25 @@ def pyopenssl_get_extensions_from_csr(csr):
critical=bool(ext.get_critical()), critical=bool(ext.get_critical()),
value=base64.b64encode(ext.get_data()), value=base64.b64encode(ext.get_data()),
) )
oid = obj2txt( try:
OpenSSL._util.lib, oid = obj2txt(
OpenSSL._util.ffi, OpenSSL._util.lib,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension) OpenSSL._util.ffi,
) OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
# This could also be done a bit simpler: )
# # This could also be done a bit simpler:
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid)) #
# # oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
# Unfortunately this gives the wrong result in case the linked OpenSSL #
# doesn't know the OID. That's why we have to get the OID dotted string # Unfortunately this gives the wrong result in case the linked OpenSSL
# similarly to how cryptography does it. # doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
except AttributeError:
# When PyOpenSSL is used with cryptography >= 35.0.0, obj2txt cannot be used.
# We try to figure out the OID with our internal lookup table, and if we fail,
# we use the short name OpenSSL returns.
oid = to_native(ext.get_short_name())
oid = OID_LOOKUP.get(oid, oid)
result[oid] = entry result[oid] = entry
return result return result

View File

@@ -32,7 +32,7 @@ from ansible.module_utils.common.text.converters import to_native, to_bytes
try: try:
from OpenSSL import crypto from OpenSSL import crypto
HAS_PYOPENSSL = True HAS_PYOPENSSL = True
except ImportError: except (ImportError, AttributeError):
# Error handled in the calling module. # Error handled in the calling module.
HAS_PYOPENSSL = False HAS_PYOPENSSL = False

View File

@@ -7,7 +7,7 @@
# their own license to the complete work. # their own license to the complete work.
# #
# Copyright (c), Entrust Datacard Corporation, 2019 # Copyright (c), Entrust Datacard Corporation, 2019
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) # Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met: # are permitted provided that the following conditions are met:

View File

@@ -21,9 +21,11 @@ __metaclass__ = type
import abc import abc
import os import os
import stat import stat
import traceback
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import ( from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import (
parse_openssh_version, parse_openssh_version,
) )
@@ -75,7 +77,14 @@ class OpensshModule(object):
self.check_mode = self.module.check_mode self.check_mode = self.module.check_mode
def execute(self): def execute(self):
self._execute() try:
self._execute()
except Exception as e:
self.module.fail_json(
msg="unexpected error occurred: %s" % to_native(e),
exception=traceback.format_exc(),
)
self.module.exit_json(**self.result) self.module.exit_json(**self.result)
@abc.abstractmethod @abc.abstractmethod

View File

@@ -21,12 +21,13 @@ __metaclass__ = type
import abc import abc
import os import os
from distutils.version import LooseVersion
from ansible.module_utils import six from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.openssh.cryptography import ( from ansible_collections.community.crypto.plugins.module_utils.openssh.cryptography import (
HAS_OPENSSH_SUPPORT, HAS_OPENSSH_SUPPORT,
HAS_OPENSSH_PRIVATE_FORMAT, HAS_OPENSSH_PRIVATE_FORMAT,
@@ -170,8 +171,10 @@ class KeypairBackend(OpensshModule):
pass pass
def _should_generate(self): def _should_generate(self):
if self.regenerate == 'never': if self.original_private_key is None:
return self.original_private_key is None return True
elif self.regenerate == 'never':
return False
elif self.regenerate == 'fail': elif self.regenerate == 'fail':
if not self._private_key_valid(): if not self._private_key_valid():
self.module.fail_json( self.module.fail_json(
@@ -179,7 +182,7 @@ class KeypairBackend(OpensshModule):
"To force regeneration, call the module with `generate` set to " + "To force regeneration, call the module with `generate` set to " +
"`partial_idempotence`, `full_idempotence` or `always`, or with `force=yes`." "`partial_idempotence`, `full_idempotence` or `always`, or with `force=yes`."
) )
return self.original_private_key is None return False
elif self.regenerate in ('partial_idempotence', 'full_idempotence'): elif self.regenerate in ('partial_idempotence', 'full_idempotence'):
return not self._private_key_valid() return not self._private_key_valid()
else: else:

View File

@@ -20,10 +20,11 @@ __metaclass__ = type
import os import os
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from distutils.version import LooseVersion
from getpass import getuser from getpass import getuser
from socket import gethostname from socket import gethostname
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
try: try:
from cryptography import __version__ as CRYPTOGRAPHY_VERSION from cryptography import __version__ as CRYPTOGRAPHY_VERSION
from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
# Once we drop support for Ansible 2.9, ansible-base 2.10, and ansible-core 2.11, we can
# remove the _version.py file, and replace the following import by
#
# from ansible.module_utils.compat.version import LooseVersion
from ._version import LooseVersion

View File

@@ -54,7 +54,7 @@ EXAMPLES = '''
- name: Check whether an account with the given account key exists - name: Check whether an account with the given account key exists
community.crypto.acme_account_info: community.crypto.acme_account_info:
account_key_src: /etc/pki/cert/private/account.key account_key_src: /etc/pki/cert/private/account.key
register: account_data register: account_data
- name: Verify that account exists - name: Verify that account exists
assert: assert:
that: that:
@@ -70,7 +70,7 @@ EXAMPLES = '''
acme_account_info: acme_account_info:
account_key_content: "{{ acme_account_key }}" account_key_content: "{{ acme_account_key }}"
account_uri: "{{ acme_account_uri }}" account_uri: "{{ acme_account_uri }}"
register: account_data register: account_data
- name: Verify that account exists - name: Verify that account exists
assert: assert:
that: that:
@@ -101,7 +101,7 @@ account:
returned: always returned: always
type: list type: list
elements: str elements: str
sample: "['mailto:me@example.com', 'tel:00123456789']" sample: ['mailto:me@example.com', 'tel:00123456789']
status: status:
description: the account's status description: the account's status
returned: always returned: always

View File

@@ -308,7 +308,7 @@ EXAMPLES = r'''
# - copy: # - copy:
# dest: /var/www/html/{{ sample_com_challenge['challenge_data']['sample.com']['http-01']['resource'] }} # dest: /var/www/html/{{ sample_com_challenge['challenge_data']['sample.com']['http-01']['resource'] }}
# content: "{{ sample_com_challenge['challenge_data']['sample.com']['http-01']['resource_value'] }}" # content: "{{ sample_com_challenge['challenge_data']['sample.com']['http-01']['resource_value'] }}"
# when: sample_com_challenge is changed and 'sample.com' in sample_com_challenge['challenge_data'] # when: sample_com_challenge is changed and 'sample.com' in sample_com_challenge['challenge_data']
# #
# Alternative way: # Alternative way:
# #
@@ -467,7 +467,20 @@ authorizations:
- Maps an identifier to ACME authorization objects. See U(https://tools.ietf.org/html/rfc8555#section-7.1.4). - Maps an identifier to ACME authorization objects. See U(https://tools.ietf.org/html/rfc8555#section-7.1.4).
returned: changed returned: changed
type: dict type: dict
sample: '{"example.com":{...}}' sample:
example.com:
identifier:
type: dns
value: example.com
status: valid
expires: '2022-08-04T01:02:03.45Z'
challenges:
- url: https://example.org/acme/challenge/12345
type: http-01
status: valid
token: A5b1C3d2E9f8G7h6
validated: '2022-08-01T01:01:02.34Z'
wildcard: false
order_uri: order_uri:
description: ACME order URI. description: ACME order URI.
returned: changed returned: changed

View File

@@ -145,6 +145,8 @@ import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.acme.errors import ModuleFailException from ansible_collections.community.crypto.plugins.module_utils.acme.errors import ModuleFailException
from ansible_collections.community.crypto.plugins.module_utils.acme.io import ( from ansible_collections.community.crypto.plugins.module_utils.acme.io import (
@@ -164,7 +166,6 @@ try:
import cryptography.x509 import cryptography.x509
import cryptography.x509.oid import cryptography.x509.oid
import ipaddress import ipaddress
from distutils.version import LooseVersion
HAS_CRYPTOGRAPHY = (LooseVersion(cryptography.__version__) >= LooseVersion('1.3')) HAS_CRYPTOGRAPHY = (LooseVersion(cryptography.__version__) >= LooseVersion('1.3'))
_cryptography_backend = cryptography.hazmat.backends.default_backend() _cryptography_backend = cryptography.hazmat.backends.default_backend()
except ImportError as dummy: except ImportError as dummy:

View File

@@ -183,7 +183,7 @@ directory:
description: The ACME directory's content description: The ACME directory's content
returned: always returned: always
type: dict type: dict
sample: | sample:
{ {
"a85k3x9f91A4": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417", "a85k3x9f91A4": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
"keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change", "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
@@ -203,7 +203,7 @@ headers:
description: The request's HTTP headers (with lowercase keys) description: The request's HTTP headers (with lowercase keys)
returned: always returned: always
type: dict type: dict
sample: | sample:
{ {
"boulder-requester": "12345", "boulder-requester": "12345",
"cache-control": "max-age=0, no-cache, no-store", "cache-control": "max-age=0, no-cache, no-store",
@@ -214,7 +214,7 @@ headers:
"cookies_string": "", "cookies_string": "",
"date": "Wed, 07 Nov 2018 12:34:56 GMT", "date": "Wed, 07 Nov 2018 12:34:56 GMT",
"expires": "Wed, 07 Nov 2018 12:44:56 GMT", "expires": "Wed, 07 Nov 2018 12:44:56 GMT",
"link": "<https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf>;rel=\"terms-of-service\"", "link": '<https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf>;rel="terms-of-service"',
"msg": "OK (904 bytes)", "msg": "OK (904 bytes)",
"pragma": "no-cache", "pragma": "no-cache",
"replay-nonce": "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGH", "replay-nonce": "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGH",

View File

@@ -124,6 +124,8 @@ import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import (
split_pem_list, split_pem_list,
) )
@@ -131,6 +133,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import
CRYPTOGRAPHY_IMP_ERR = None CRYPTOGRAPHY_IMP_ERR = None
try: try:
import cryptography import cryptography
import cryptography.exceptions
import cryptography.hazmat.backends import cryptography.hazmat.backends
import cryptography.hazmat.primitives.serialization import cryptography.hazmat.primitives.serialization
import cryptography.hazmat.primitives.asymmetric.rsa import cryptography.hazmat.primitives.asymmetric.rsa
@@ -140,7 +143,6 @@ try:
import cryptography.hazmat.primitives.asymmetric.utils import cryptography.hazmat.primitives.asymmetric.utils
import cryptography.x509 import cryptography.x509
import cryptography.x509.oid import cryptography.x509.oid
from distutils.version import LooseVersion
HAS_CRYPTOGRAPHY = (LooseVersion(cryptography.__version__) >= LooseVersion('1.5')) HAS_CRYPTOGRAPHY = (LooseVersion(cryptography.__version__) >= LooseVersion('1.5'))
_cryptography_backend = cryptography.hazmat.backends.default_backend() _cryptography_backend = cryptography.hazmat.backends.default_backend()
except ImportError as dummy: except ImportError as dummy:
@@ -189,6 +191,9 @@ def is_parent(module, cert, potential_parent):
return True return True
except cryptography.exceptions.InvalidSignature as dummy: except cryptography.exceptions.InvalidSignature as dummy:
return False return False
except cryptography.exceptions.UnsupportedAlgorithm as dummy:
module.warn('Unsupported algorithm "{0}"'.format(cert.cert.signature_hash_algorithm))
return False
except Exception as e: except Exception as e:
module.fail_json(msg='Unknown error on signature validation: {0}'.format(e)) module.fail_json(msg='Unknown error on signature validation: {0}'.format(e))
@@ -236,13 +241,17 @@ class CertificateSet(object):
def __init__(self, module): def __init__(self, module):
self.module = module self.module = module
self.certificates = set() self.certificates = set()
self.certificate_by_issuer = dict() self.certificates_by_issuer = dict()
self.certificate_by_cert = dict()
def _load_file(self, path): def _load_file(self, path):
certs = load_PEM_list(self.module, path, fail_on_error=False) certs = load_PEM_list(self.module, path, fail_on_error=False)
for cert in certs: for cert in certs:
self.certificates.add(cert) self.certificates.add(cert)
self.certificate_by_issuer[cert.cert.subject] = cert if cert.cert.subject not in self.certificates_by_issuer:
self.certificates_by_issuer[cert.cert.subject] = []
self.certificates_by_issuer[cert.cert.subject].append(cert)
self.certificate_by_cert[cert.cert] = cert
def load(self, path): def load(self, path):
''' '''
@@ -260,8 +269,8 @@ class CertificateSet(object):
''' '''
Search for the parent (issuer) of a certificate. Return ``None`` if none was found. Search for the parent (issuer) of a certificate. Return ``None`` if none was found.
''' '''
potential_parent = self.certificate_by_issuer.get(cert.cert.issuer) potential_parents = self.certificates_by_issuer.get(cert.cert.issuer, [])
if potential_parent is not None: for potential_parent in potential_parents:
if is_parent(self.module, cert, potential_parent): if is_parent(self.module, cert, potential_parent):
return potential_parent return potential_parent
return None return None
@@ -274,6 +283,16 @@ def format_cert(cert):
return str(cert.cert) return str(cert.cert)
def check_cycle(module, occured_certificates, next):
'''
Make sure that next is not in occured_certificates so far, and add it.
'''
next_cert = next.cert
if next_cert in occured_certificates:
module.fail_json(msg='Found cycle while building certificate chain')
occured_certificates.add(next_cert)
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec=dict( argument_spec=dict(
@@ -312,13 +331,19 @@ def main():
# Try to complete chain # Try to complete chain
current = chain[-1] current = chain[-1]
completed = [] completed = []
occured_certificates = set([cert.cert for cert in chain])
if current.cert in roots.certificate_by_cert:
# Don't try to complete the chain when it's already ending with a root certificate
current = None
while current: while current:
root = roots.find_parent(current) root = roots.find_parent(current)
if root: if root:
check_cycle(module, occured_certificates, root)
completed.append(root) completed.append(root)
break break
intermediate = intermediates.find_parent(current) intermediate = intermediates.find_parent(current)
if intermediate: if intermediate:
check_cycle(module, occured_certificates, intermediate)
completed.append(intermediate) completed.append(intermediate)
current = intermediate current = intermediate
else: else:

View File

@@ -519,11 +519,11 @@ import re
import time import time
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_bytes from ansible.module_utils.common.text.converters import to_native, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import ( from ansible_collections.community.crypto.plugins.module_utils.io import (
write_file, write_file,
) )
@@ -922,8 +922,8 @@ def main():
module.fail_json(msg='The cert_expiry field is invalid when request_type="reissue".') module.fail_json(msg='The cert_expiry field is invalid when request_type="reissue".')
elif module.params['cert_lifetime']: elif module.params['cert_lifetime']:
module.fail_json(msg='The cert_lifetime field is invalid when request_type="reissue".') module.fail_json(msg='The cert_lifetime field is invalid when request_type="reissue".')
# Only a reissued request can omit the CSR # Reissued or renew request can omit the CSR
else: elif module.params['request_type'] != 'renew':
module_params_csr = module.params['csr'] module_params_csr = module.params['csr']
if module_params_csr is None: if module_params_csr is None:
module.fail_json(msg='The csr field is required when request_type={0}'.format(module.params['request_type'])) module.fail_json(msg='The csr field is required when request_type={0}'.format(module.params['request_type']))

View File

@@ -167,7 +167,6 @@ import base64
import datetime import datetime
import traceback import traceback
from distutils.version import LooseVersion
from os.path import isfile from os.path import isfile
from socket import create_connection, setdefaulttimeout, socket from socket import create_connection, setdefaulttimeout, socket
from ssl import get_server_certificate, DER_cert_to_PEM_cert, CERT_NONE, CERT_REQUIRED from ssl import get_server_certificate, DER_cert_to_PEM_cert, CERT_NONE, CERT_REQUIRED
@@ -175,6 +174,8 @@ from ssl import get_server_certificate, DER_cert_to_PEM_cert, CERT_NONE, CERT_RE
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_bytes
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
cryptography_oid_to_name, cryptography_oid_to_name,
cryptography_get_extensions_from_cert, cryptography_get_extensions_from_cert,
@@ -197,7 +198,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -350,12 +350,40 @@ STDERR = 2
# used to get <luks-name> out of lsblk output in format 'crypt <luks-name>' # used to get <luks-name> out of lsblk output in format 'crypt <luks-name>'
# regex takes care of any possible blank characters # regex takes care of any possible blank characters
LUKS_NAME_REGEX = re.compile(r'\s*crypt\s+([^\s]*)\s*') LUKS_NAME_REGEX = re.compile(r'^crypt\s+([^\s]*)\s*$')
# used to get </luks/device> out of lsblk output # used to get </luks/device> out of lsblk output
# in format 'device: </luks/device>' # in format 'device: </luks/device>'
LUKS_DEVICE_REGEX = re.compile(r'\s*device:\s+([^\s]*)\s*') LUKS_DEVICE_REGEX = re.compile(r'\s*device:\s+([^\s]*)\s*')
# See https://gitlab.com/cryptsetup/cryptsetup/-/wikis/LUKS-standard/on-disk-format.pdf
LUKS_HEADER = b'LUKS\xba\xbe'
LUKS_HEADER_L = 6
# See https://gitlab.com/cryptsetup/LUKS2-docs/-/blob/master/luks2_doc_wip.pdf
LUKS2_HEADER_OFFSETS = [0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000]
LUKS2_HEADER2 = b'SKUL\xba\xbe'
def wipe_luks_headers(device):
wipe_offsets = []
with open(device, 'rb') as f:
# f.seek(0)
data = f.read(LUKS_HEADER_L)
if data == LUKS_HEADER:
wipe_offsets.append(0)
for offset in LUKS2_HEADER_OFFSETS:
f.seek(offset)
data = f.read(LUKS_HEADER_L)
if data == LUKS2_HEADER2:
wipe_offsets.append(offset)
if wipe_offsets:
with open(device, 'wb') as f:
for offset in wipe_offsets:
f.seek(offset)
f.write(b'\x00\x00\x00\x00\x00\x00')
class Handler(object): class Handler(object):
def __init__(self, module): def __init__(self, module):
@@ -418,13 +446,11 @@ class CryptHandler(Handler):
raise ValueError('Error while obtaining LUKS name for %s: %s' raise ValueError('Error while obtaining LUKS name for %s: %s'
% (device, result[STDERR])) % (device, result[STDERR]))
m = LUKS_NAME_REGEX.search(result[STDOUT]) for line in result[STDOUT].splitlines(False):
m = LUKS_NAME_REGEX.match(line)
try: if m:
name = m.group(1) return m.group(1)
except AttributeError: return None
name = None
return name
def get_container_device_by_name(self, name): def get_container_device_by_name(self, name):
''' obtain device name based on the LUKS container name ''' obtain device name based on the LUKS container name
@@ -515,9 +541,17 @@ class CryptHandler(Handler):
self.run_luks_close(name) self.run_luks_close(name)
result = self._run_command([wipefs_bin, '--all', device]) result = self._run_command([wipefs_bin, '--all', device])
if result[RETURN_CODE] != 0: if result[RETURN_CODE] != 0:
raise ValueError('Error while wiping luks container %s: %s' raise ValueError('Error while wiping LUKS container signatures for %s: %s'
% (device, result[STDERR])) % (device, result[STDERR]))
# For LUKS2, sometimes both `cryptsetup erase` and `wipefs` do **not**
# erase all LUKS signatures (they seem to miss the second header). That's
# why we do it ourselves here.
try:
wipe_luks_headers(device)
except Exception as exc:
raise ValueError('Error while wiping LUKS container signatures for %s: %s' % (device, exc))
def run_luks_add_key(self, device, keyfile, passphrase, new_keyfile, def run_luks_add_key(self, device, keyfile, passphrase, new_keyfile,
new_passphrase, pbkdf): new_passphrase, pbkdf):
''' Add new key from a keyfile or passphrase to given 'device'; ''' Add new key from a keyfile or passphrase to given 'device';
@@ -785,6 +819,7 @@ def run_module():
module = AnsibleModule(argument_spec=module_args, module = AnsibleModule(argument_spec=module_args,
supports_check_mode=True, supports_check_mode=True,
mutually_exclusive=mutually_exclusive) mutually_exclusive=mutually_exclusive)
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
if module.params['device'] is not None: if module.params['device'] is not None:
try: try:

View File

@@ -258,11 +258,12 @@ info:
''' '''
import os import os
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.text.converters import to_native, to_text
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.common import ( from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.common import (
KeygenCommand, KeygenCommand,
OpensshModule, OpensshModule,
@@ -378,7 +379,7 @@ class Certificate(OpensshModule):
def _is_fully_valid(self): def _is_fully_valid(self):
return self._is_partially_valid() and all([ return self._is_partially_valid() and all([
self._compare_options(), self._compare_options() if self.original_data.type == 'user' else True,
self.original_data.key_id == self.identifier, self.original_data.key_id == self.identifier,
self.original_data.public_key == self._get_key_fingerprint(self.public_key), self.original_data.public_key == self._get_key_fingerprint(self.public_key),
self.original_data.signing_key == self._get_key_fingerprint(self.signing_key), self.original_data.signing_key == self._get_key_fingerprint(self.signing_key),

View File

@@ -178,7 +178,7 @@ public_key:
description: The public key of the generated SSH private key. description: The public key of the generated SSH private key.
returned: changed or success returned: changed or success
type: str type: str
sample: ssh-rsa AAAAB3Nza(...omitted...)veL4E3Xcw== test_key sample: ssh-rsa AAAAB3Nza(...omitted...)veL4E3Xcw==
comment: comment:
description: The comment of the generated key. description: The comment of the generated key.
returned: changed or success returned: changed or success

View File

@@ -177,7 +177,7 @@ subject:
returned: changed or success returned: changed or success
type: list type: list
elements: list elements: list
sample: "[('CN', 'www.ansible.com'), ('O', 'Ansible')]" sample: [['CN', 'www.ansible.com'], ['O', 'Ansible']]
subjectAltName: subjectAltName:
description: The alternative names this CSR is valid for description: The alternative names this CSR is valid for
returned: changed or success returned: changed or success
@@ -329,9 +329,10 @@ def main():
if not os.path.isdir(base_dir): if not os.path.isdir(base_dir):
module.fail_json(name=base_dir, msg='The directory %s does not exist or the file is not a directory' % base_dir) module.fail_json(name=base_dir, msg='The directory %s does not exist or the file is not a directory' % base_dir)
backend = module.params['select_crypto_backend']
backend, module_backend = select_backend(module, backend)
try: try:
backend = module.params['select_crypto_backend']
backend, module_backend = select_backend(module, backend)
csr = CertificateSigningRequestModule(module, module_backend) csr = CertificateSigningRequestModule(module, module_backend)
if module.params['state'] == 'present': if module.params['state'] == 'present':
csr.generate(module) csr.generate(module)

View File

@@ -85,7 +85,7 @@ basic_constraints:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[CA:TRUE, pathlen:1]" sample: ['CA:TRUE', 'pathlen:1']
basic_constraints_critical: basic_constraints_critical:
description: Whether the C(basic_constraints) extension is critical. description: Whether the C(basic_constraints) extension is critical.
returned: success returned: success
@@ -95,7 +95,7 @@ extended_key_usage:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[Biometric Info, DVCS, Time Stamping]" sample: [Biometric Info, DVCS, Time Stamping]
extended_key_usage_critical: extended_key_usage_critical:
description: Whether the C(extended_key_usage) extension is critical. description: Whether the C(extended_key_usage) extension is critical.
returned: success returned: success
@@ -114,12 +114,12 @@ extensions_by_oid:
returned: success returned: success
type: str type: str
sample: "MAMCAQU=" sample: "MAMCAQU="
sample: '{"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}' sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage: key_usage:
description: Entries in the C(key_usage) extension, or C(none) if extension is not present. description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
returned: success returned: success
type: str type: str
sample: "[Key Agreement, Data Encipherment]" sample: [Key Agreement, Data Encipherment]
key_usage_critical: key_usage_critical:
description: Whether the C(key_usage) extension is critical. description: Whether the C(key_usage) extension is critical.
returned: success returned: success
@@ -129,7 +129,7 @@ subject_alt_name:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[DNS:www.ansible.com, IP:1.2.3.4]" sample: ["DNS:www.ansible.com", "IP:1.2.3.4"]
subject_alt_name_critical: subject_alt_name_critical:
description: Whether the C(subject_alt_name) extension is critical. description: Whether the C(subject_alt_name) extension is critical.
returned: success returned: success
@@ -171,13 +171,13 @@ subject:
- Note that for repeated values, only the last one will be returned. - Note that for repeated values, only the last one will be returned.
returned: success returned: success
type: dict type: dict
sample: '{"commonName": "www.example.com", "emailAddress": "test@example.com"}' sample: {"commonName": "www.example.com", "emailAddress": "test@example.com"}
subject_ordered: subject_ordered:
description: The CSR's subject as an ordered list of tuples. description: The CSR's subject as an ordered list of tuples.
returned: success returned: success
type: list type: list
elements: list elements: list
sample: '[["commonName", "www.example.com"], ["emailAddress": "test@example.com"]]' sample: [["commonName", "www.example.com"], ["emailAddress": "test@example.com"]]
public_key: public_key:
description: CSR's public key in PEM format description: CSR's public key in PEM format
returned: success returned: success
@@ -285,14 +285,14 @@ authority_cert_issuer:
returned: success and if the pyOpenSSL backend is I(not) used returned: success and if the pyOpenSSL backend is I(not) used
type: list type: list
elements: str elements: str
sample: "[DNS:www.ansible.com, IP:1.2.3.4]" sample: ["DNS:www.ansible.com", "IP:1.2.3.4"]
authority_cert_serial_number: authority_cert_serial_number:
description: description:
- The CSR's authority cert serial number. - The CSR's authority cert serial number.
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success and if the pyOpenSSL backend is I(not) used returned: success and if the pyOpenSSL backend is I(not) used
type: int type: int
sample: '12345' sample: 12345
''' '''

View File

@@ -66,7 +66,7 @@ subject:
returned: changed or success returned: changed or success
type: list type: list
elements: list elements: list
sample: "[('CN', 'www.ansible.com'), ('O', 'Ansible')]" sample: [['CN', 'www.ansible.com'], ['O', 'Ansible']]
subjectAltName: subjectAltName:
description: The alternative names this CSR is valid for description: The alternative names this CSR is valid for
returned: changed or success returned: changed or success
@@ -160,9 +160,10 @@ def main():
supports_check_mode=True, supports_check_mode=True,
) )
backend = module.params['select_crypto_backend']
backend, module_backend = select_backend(module, backend)
try: try:
backend = module.params['select_crypto_backend']
backend, module_backend = select_backend(module, backend)
csr = CertificateSigningRequestModule(module, module_backend) csr = CertificateSigningRequestModule(module, module_backend)
csr.generate(module) csr.generate(module)
result = csr.dump() result = csr.dump()

View File

@@ -128,11 +128,11 @@ import re
import tempfile import tempfile
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import ( from ansible_collections.community.crypto.plugins.module_utils.io import (
load_file_if_exists, load_file_if_exists,
write_file, write_file,
@@ -333,7 +333,7 @@ class DHParameterCryptography(DHParameterBase):
try: try:
with open(self.path, 'rb') as f: with open(self.path, 'rb') as f:
data = f.read() data = f.read()
params = self.crypto_backend.load_pem_parameters(data) params = cryptography.hazmat.primitives.serialization.load_pem_parameters(data, backend=self.crypto_backend)
except Exception as dummy: except Exception as dummy:
return False return False
# Check parameters # Check parameters

View File

@@ -23,7 +23,7 @@ description:
# Please note that the C(pyopenssl) backend has been deprecated in community.crypto x.y.0, # Please note that the C(pyopenssl) backend has been deprecated in community.crypto x.y.0,
# and will be removed in community.crypto (x+1).0.0. # and will be removed in community.crypto (x+1).0.0.
requirements: requirements:
- PyOpenSSL >= 0.15 or cryptography >= 3.0 - PyOpenSSL >= 0.15, < 23.3.0 or cryptography >= 3.0
options: options:
action: action:
description: description:
@@ -239,11 +239,11 @@ import os
import stat import stat
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes, to_native from ansible.module_utils.common.text.converters import to_bytes, to_native
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import ( from ansible_collections.community.crypto.plugins.module_utils.io import (
load_file_if_exists, load_file_if_exists,
write_file, write_file,
@@ -270,13 +270,15 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import
MINIMAL_CRYPTOGRAPHY_VERSION = '3.0' MINIMAL_CRYPTOGRAPHY_VERSION = '3.0'
MINIMAL_PYOPENSSL_VERSION = '0.15' MINIMAL_PYOPENSSL_VERSION = '0.15'
MAXIMAL_PYOPENSSL_VERSION = '23.3.0'
PYOPENSSL_IMP_ERR = None PYOPENSSL_IMP_ERR = None
try: try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
from OpenSSL.crypto import load_pkcs12 as _load_pkcs12 # this got removed in pyOpenSSL 23.3.0
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:
@@ -542,6 +544,8 @@ class PkcsPyOpenSSL(Pkcs):
return crypto.dump_certificate(crypto.FILETYPE_PEM, cert) if cert else None return crypto.dump_certificate(crypto.FILETYPE_PEM, cert) if cert else None
def _dump_other_certificates(self, pkcs12): def _dump_other_certificates(self, pkcs12):
if pkcs12.get_ca_certificates() is None:
return []
return [ return [
crypto.dump_certificate(crypto.FILETYPE_PEM, other_cert) crypto.dump_certificate(crypto.FILETYPE_PEM, other_cert)
for other_cert in pkcs12.get_ca_certificates() for other_cert in pkcs12.get_ca_certificates()
@@ -635,7 +639,11 @@ def select_backend(module, backend):
if backend == 'auto': if backend == 'auto':
# Detection what is possible # Detection what is possible
can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION)
can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) can_use_pyopenssl = (
PYOPENSSL_FOUND and
PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) and
PYOPENSSL_VERSION < LooseVersion(MAXIMAL_PYOPENSSL_VERSION)
)
# If no restrictions are provided, first try cryptography, then pyOpenSSL # If no restrictions are provided, first try cryptography, then pyOpenSSL
if module.params['iter_size'] is not None or module.params['maciter_size'] is not None: if module.params['iter_size'] is not None or module.params['maciter_size'] is not None:
@@ -649,14 +657,17 @@ def select_backend(module, backend):
# Success? # Success?
if backend == 'auto': if backend == 'auto':
module.fail_json(msg=("Can't detect any of the required Python libraries " module.fail_json(msg=("Can't detect any of the required Python libraries "
"cryptography (>= {0}) or PyOpenSSL (>= {1})").format( "cryptography (>= {0}) or PyOpenSSL (>= {1}, < {2})").format(
MINIMAL_CRYPTOGRAPHY_VERSION, MINIMAL_CRYPTOGRAPHY_VERSION,
MINIMAL_PYOPENSSL_VERSION)) MINIMAL_PYOPENSSL_VERSION,
MAXIMAL_PYOPENSSL_VERSION))
if backend == 'pyopenssl': if backend == 'pyopenssl':
if not PYOPENSSL_FOUND: if not PYOPENSSL_FOUND:
module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), msg = missing_required_lib(
exception=PYOPENSSL_IMP_ERR) 'pyOpenSSL >= {0}, < {1}'.format(MINIMAL_PYOPENSSL_VERSION, MAXIMAL_PYOPENSSL_VERSION)
)
module.fail_json(msg=msg, exception=PYOPENSSL_IMP_ERR)
# module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', # module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated',
# version='x.0.0', collection_name='community.crypto') # version='x.0.0', collection_name='community.crypto')
return backend, PkcsPyOpenSSL(module) return backend, PkcsPyOpenSSL(module)

View File

@@ -102,6 +102,9 @@ key_is_consistent:
- Whether the key is consistent. Can also return C(none) next to C(yes) and - Whether the key is consistent. Can also return C(none) next to C(yes) and
C(no), to indicate that consistency could not be checked. C(no), to indicate that consistency could not be checked.
- In case the check returns C(no), the module will fail. - In case the check returns C(no), the module will fail.
- Note that consistency checks only work for certain key types, and might depend on the
version of the cryptography library. For example, with cryptography 42.0.0 and newer
consistency of RSA keys can no longer be checked.
returned: always returned: always
type: bool type: bool
public_key: public_key:

View File

@@ -51,7 +51,6 @@ seealso:
EXAMPLES = r''' EXAMPLES = r'''
- name: Generate an OpenSSL private key with the default values (4096 bits, RSA) - name: Generate an OpenSSL private key with the default values (4096 bits, RSA)
community.crypto.openssl_privatekey_pipe: community.crypto.openssl_privatekey_pipe:
path: /etc/ssl/private/ansible.com.pem
register: output register: output
no_log: true # make sure that private key data is not accidentally revealed in logs! no_log: true # make sure that private key data is not accidentally revealed in logs!
- name: Show generated key - name: Show generated key

View File

@@ -13,8 +13,9 @@ DOCUMENTATION = r'''
module: openssl_publickey module: openssl_publickey
short_description: Generate an OpenSSL public key from its private key. short_description: Generate an OpenSSL public key from its private key.
description: description:
- This module allows one to (re)generate OpenSSL public keys from their private keys. - This module allows one to (re)generate public keys from their private keys.
- Keys are generated in PEM or OpenSSH format. - Public keys are generated in PEM or OpenSSH format. Private keys must be OpenSSL PEM keys.
OpenSSH private keys are not supported, use the M(community.crypto.openssh_keypair) module to manage these.
- "The module can use the cryptography Python library, or the pyOpenSSL Python - "The module can use the cryptography Python library, or the pyOpenSSL Python
library. By default, it tries to detect which one is available. This can be library. By default, it tries to detect which one is available. This can be
overridden with the I(select_crypto_backend) option. When I(format) is C(OpenSSH), overridden with the I(select_crypto_backend) option. When I(format) is C(OpenSSH),
@@ -182,11 +183,11 @@ publickey:
import os import os
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import ( from ansible_collections.community.crypto.plugins.module_utils.io import (
load_file_if_exists, load_file_if_exists,
write_file, write_file,
@@ -217,7 +218,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -61,7 +61,7 @@ EXAMPLES = r'''
path: /etc/ssl/private/ansible.com.pem path: /etc/ssl/private/ansible.com.pem
- name: Create public key from private key - name: Create public key from private key
community.crypto.openssl_privatekey: community.crypto.openssl_publickey:
privatekey_path: /etc/ssl/private/ansible.com.pem privatekey_path: /etc/ssl/private/ansible.com.pem
path: /etc/ssl/ansible.com.pub path: /etc/ssl/ansible.com.pub

View File

@@ -96,9 +96,10 @@ signature:
import os import os
import traceback import traceback
from distutils.version import LooseVersion
import base64 import base64
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
MINIMAL_PYOPENSSL_VERSION = '0.11' MINIMAL_PYOPENSSL_VERSION = '0.11'
MINIMAL_CRYPTOGRAPHY_VERSION = '1.4' MINIMAL_CRYPTOGRAPHY_VERSION = '1.4'
@@ -107,7 +108,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -96,9 +96,10 @@ valid:
import os import os
import traceback import traceback
from distutils.version import LooseVersion
import base64 import base64
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
MINIMAL_PYOPENSSL_VERSION = '0.11' MINIMAL_PYOPENSSL_VERSION = '0.11'
MINIMAL_CRYPTOGRAPHY_VERSION = '1.4' MINIMAL_CRYPTOGRAPHY_VERSION = '1.4'
@@ -107,7 +108,7 @@ try:
import OpenSSL import OpenSSL
from OpenSSL import crypto from OpenSSL import crypto
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except ImportError: except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc() PYOPENSSL_IMP_ERR = traceback.format_exc()
PYOPENSSL_FOUND = False PYOPENSSL_FOUND = False
else: else:

View File

@@ -129,7 +129,7 @@ basic_constraints:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[CA:TRUE, pathlen:1]" sample: ["CA:TRUE", "pathlen:1"]
basic_constraints_critical: basic_constraints_critical:
description: Whether the C(basic_constraints) extension is critical. description: Whether the C(basic_constraints) extension is critical.
returned: success returned: success
@@ -139,7 +139,7 @@ extended_key_usage:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[Biometric Info, DVCS, Time Stamping]" sample: [Biometric Info, DVCS, Time Stamping]
extended_key_usage_critical: extended_key_usage_critical:
description: Whether the C(extended_key_usage) extension is critical. description: Whether the C(extended_key_usage) extension is critical.
returned: success returned: success
@@ -158,12 +158,12 @@ extensions_by_oid:
returned: success returned: success
type: str type: str
sample: "MAMCAQU=" sample: "MAMCAQU="
sample: '{"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}' sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage: key_usage:
description: Entries in the C(key_usage) extension, or C(none) if extension is not present. description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
returned: success returned: success
type: str type: str
sample: "[Key Agreement, Data Encipherment]" sample: [Key Agreement, Data Encipherment]
key_usage_critical: key_usage_critical:
description: Whether the C(key_usage) extension is critical. description: Whether the C(key_usage) extension is critical.
returned: success returned: success
@@ -173,7 +173,7 @@ subject_alt_name:
returned: success returned: success
type: list type: list
elements: str elements: str
sample: "[DNS:www.ansible.com, IP:1.2.3.4]" sample: ["DNS:www.ansible.com", "IP:1.2.3.4"]
subject_alt_name_critical: subject_alt_name_critical:
description: Whether the C(subject_alt_name) extension is critical. description: Whether the C(subject_alt_name) extension is critical.
returned: success returned: success
@@ -192,36 +192,36 @@ issuer:
- Note that for repeated values, only the last one will be returned. - Note that for repeated values, only the last one will be returned.
returned: success returned: success
type: dict type: dict
sample: '{"organizationName": "Ansible", "commonName": "ca.example.com"}' sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
issuer_ordered: issuer_ordered:
description: The certificate's issuer as an ordered list of tuples. description: The certificate's issuer as an ordered list of tuples.
returned: success returned: success
type: list type: list
elements: list elements: list
sample: '[["organizationName", "Ansible"], ["commonName": "ca.example.com"]]' sample: [["organizationName", "Ansible"], ["commonName": "ca.example.com"]]
subject: subject:
description: description:
- The certificate's subject as a dictionary. - The certificate's subject as a dictionary.
- Note that for repeated values, only the last one will be returned. - Note that for repeated values, only the last one will be returned.
returned: success returned: success
type: dict type: dict
sample: '{"commonName": "www.example.com", "emailAddress": "test@example.com"}' sample: {"commonName": "www.example.com", "emailAddress": "test@example.com"}
subject_ordered: subject_ordered:
description: The certificate's subject as an ordered list of tuples. description: The certificate's subject as an ordered list of tuples.
returned: success returned: success
type: list type: list
elements: list elements: list
sample: '[["commonName", "www.example.com"], ["emailAddress": "test@example.com"]]' sample: [["commonName", "www.example.com"], ["emailAddress": "test@example.com"]]
not_after: not_after:
description: C(notAfter) date as ASN.1 TIME. description: C(notAfter) date as ASN.1 TIME.
returned: success returned: success
type: str type: str
sample: 20190413202428Z sample: '20190413202428Z'
not_before: not_before:
description: C(notBefore) date as ASN.1 TIME. description: C(notBefore) date as ASN.1 TIME.
returned: success returned: success
type: str type: str
sample: 20190331202428Z sample: '20190331202428Z'
public_key: public_key:
description: Certificate's public key in PEM format. description: Certificate's public key in PEM format.
returned: success returned: success
@@ -359,14 +359,14 @@ authority_cert_issuer:
returned: success and if the pyOpenSSL backend is I(not) used returned: success and if the pyOpenSSL backend is I(not) used
type: list type: list
elements: str elements: str
sample: "[DNS:www.ansible.com, IP:1.2.3.4]" sample: ["DNS:www.ansible.com", "IP:1.2.3.4"]
authority_cert_serial_number: authority_cert_serial_number:
description: description:
- The certificate's authority cert serial number. - The certificate's authority cert serial number.
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success and if the pyOpenSSL backend is I(not) used returned: success and if the pyOpenSSL backend is I(not) used
type: int type: int
sample: '12345' sample: 12345
ocsp_uri: ocsp_uri:
description: The OCSP responder URI, if included in the certificate. Will be description: The OCSP responder URI, if included in the certificate. Will be
C(none) if no OCSP responder URI is included. C(none) if no OCSP responder URI is included.

View File

@@ -286,13 +286,13 @@ issuer:
- Note that for repeated values, only the last one will be returned. - Note that for repeated values, only the last one will be returned.
returned: success returned: success
type: dict type: dict
sample: '{"organizationName": "Ansible", "commonName": "ca.example.com"}' sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
issuer_ordered: issuer_ordered:
description: The CRL's issuer as an ordered list of tuples. description: The CRL's issuer as an ordered list of tuples.
returned: success returned: success
type: list type: list
elements: list elements: list
sample: '[["organizationName", "Ansible"], ["commonName": "ca.example.com"]]' sample: [["organizationName", "Ansible"], ["commonName": "ca.example.com"]]
last_update: last_update:
description: The point in time from which this CRL can be trusted as ASN.1 TIME. description: The point in time from which this CRL can be trusted as ASN.1 TIME.
returned: success returned: success
@@ -326,7 +326,7 @@ revoked_certificates:
description: The certificate's issuer. description: The certificate's issuer.
type: list type: list
elements: str elements: str
sample: '["DNS:ca.example.org"]' sample: ["DNS:ca.example.org"]
issuer_critical: issuer_critical:
description: Whether the certificate issuer extension is critical. description: Whether the certificate issuer extension is critical.
type: bool type: bool
@@ -367,11 +367,11 @@ import base64
import os import os
import traceback import traceback
from distutils.version import LooseVersion
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.text.converters import to_native, to_text
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import ( from ansible_collections.community.crypto.plugins.module_utils.io import (
write_file, write_file,
) )
@@ -392,6 +392,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
cryptography_get_name, cryptography_get_name,
cryptography_key_needs_digest_for_signing,
cryptography_name_to_oid, cryptography_name_to_oid,
cryptography_oid_to_name, cryptography_oid_to_name,
cryptography_serial_number_of_cert, cryptography_serial_number_of_cert,
@@ -612,8 +613,12 @@ class CRL(OpenSSLObject):
return False return False
if self.next_update != self.crl.next_update and not self.ignore_timestamps: if self.next_update != self.crl.next_update and not self.ignore_timestamps:
return False return False
if self.digest.name != self.crl.signature_hash_algorithm.name: if cryptography_key_needs_digest_for_signing(self.privatekey):
return False if self.crl.signature_hash_algorithm is None or self.digest.name != self.crl.signature_hash_algorithm.name:
return False
else:
if self.crl.signature_hash_algorithm is not None:
return False
want_issuer = [(cryptography_name_to_oid(entry[0]), entry[1]) for entry in self.issuer] want_issuer = [(cryptography_name_to_oid(entry[0]), entry[1]) for entry in self.issuer]
if want_issuer != [(sub.oid, sub.value) for sub in self.crl.issuer]: if want_issuer != [(sub.oid, sub.value) for sub in self.crl.issuer]:
@@ -664,9 +669,7 @@ class CRL(OpenSSLObject):
revoked_cert = revoked_cert.revocation_date(entry['revocation_date']) revoked_cert = revoked_cert.revocation_date(entry['revocation_date'])
if entry['issuer'] is not None: if entry['issuer'] is not None:
revoked_cert = revoked_cert.add_extension( revoked_cert = revoked_cert.add_extension(
x509.CertificateIssuer([ x509.CertificateIssuer(entry['issuer']),
cryptography_get_name(name, 'issuer') for name in entry['issuer']
]),
entry['issuer_critical'] entry['issuer_critical']
) )
if entry['reason'] is not None: if entry['reason'] is not None:
@@ -681,7 +684,10 @@ class CRL(OpenSSLObject):
) )
crl = crl.add_revoked_certificate(revoked_cert.build(backend)) crl = crl.add_revoked_certificate(revoked_cert.build(backend))
self.crl = crl.sign(self.privatekey, self.digest, backend=backend) digest = None
if cryptography_key_needs_digest_for_signing(self.privatekey):
digest = self.digest
self.crl = crl.sign(self.privatekey, digest, backend=backend)
if self.format == 'pem': if self.format == 'pem':
return self.crl.public_bytes(Encoding.PEM) return self.crl.public_bytes(Encoding.PEM)
else: else:

View File

@@ -78,23 +78,23 @@ issuer:
- Note that for repeated values, only the last one will be returned. - Note that for repeated values, only the last one will be returned.
returned: success returned: success
type: dict type: dict
sample: '{"organizationName": "Ansible", "commonName": "ca.example.com"}' sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
issuer_ordered: issuer_ordered:
description: The CRL's issuer as an ordered list of tuples. description: The CRL's issuer as an ordered list of tuples.
returned: success returned: success
type: list type: list
elements: list elements: list
sample: '[["organizationName", "Ansible"], ["commonName": "ca.example.com"]]' sample: [["organizationName", "Ansible"], ["commonName": "ca.example.com"]]
last_update: last_update:
description: The point in time from which this CRL can be trusted as ASN.1 TIME. description: The point in time from which this CRL can be trusted as ASN.1 TIME.
returned: success returned: success
type: str type: str
sample: 20190413202428Z sample: '20190413202428Z'
next_update: next_update:
description: The point in time from which a new CRL will be issued and the client has to check for it as ASN.1 TIME. description: The point in time from which a new CRL will be issued and the client has to check for it as ASN.1 TIME.
returned: success returned: success
type: str type: str
sample: 20190413202428Z sample: '20190413202428Z'
digest: digest:
description: The signature algorithm used to sign the CRL. description: The signature algorithm used to sign the CRL.
returned: success returned: success
@@ -113,12 +113,12 @@ revoked_certificates:
revocation_date: revocation_date:
description: The point in time the certificate was revoked as ASN.1 TIME. description: The point in time the certificate was revoked as ASN.1 TIME.
type: str type: str
sample: 20190413202428Z sample: '20190413202428Z'
issuer: issuer:
description: The certificate's issuer. description: The certificate's issuer.
type: list type: list
elements: str elements: str
sample: '["DNS:ca.example.org"]' sample: ["DNS:ca.example.org"]
issuer_critical: issuer_critical:
description: Whether the certificate issuer extension is critical. description: Whether the certificate issuer extension is critical.
type: bool type: bool
@@ -140,7 +140,7 @@ revoked_certificates:
The point in time it was known/suspected that the private key was compromised The point in time it was known/suspected that the private key was compromised
or that the certificate otherwise became invalid as ASN.1 TIME. or that the certificate otherwise became invalid as ASN.1 TIME.
type: str type: str
sample: 20190413202428Z sample: '20190413202428Z'
invalidity_date_critical: invalidity_date_critical:
description: Whether the invalidity date extension is critical. description: Whether the invalidity date extension is critical.
type: bool type: bool

View File

@@ -115,13 +115,12 @@ class AnsibleActionModule(object):
self.required_by = required_by self.required_by = required_by
self._diff = self.__action_plugin._play_context.diff self._diff = self.__action_plugin._play_context.diff
self._verbosity = self.__action_plugin._display.verbosity self._verbosity = self.__action_plugin._display.verbosity
self._string_conversion_action = C.STRING_CONVERSION_ACTION
self.aliases = {} self.aliases = {}
self._legal_inputs = [] self._legal_inputs = []
self._options_context = list() self._options_context = list()
self.params = copy.deepcopy(action_plugin._task.args) self.params = copy.deepcopy(self.__action_plugin._task.args)
self.no_log_values = set() self.no_log_values = set()
if HAS_ARGSPEC_VALIDATOR: if HAS_ARGSPEC_VALIDATOR:
self._validator = ArgumentSpecValidator( self._validator = ArgumentSpecValidator(
@@ -145,9 +144,14 @@ class AnsibleActionModule(object):
# warnings and deprecations that do not work in plugins. This is a copy of that code adjusted # warnings and deprecations that do not work in plugins. This is a copy of that code adjusted
# for our use-case: # for our use-case:
for d in self._validation_result._deprecations: for d in self._validation_result._deprecations:
self.deprecate( # Before ansible-core 2.14.2, deprecations were always for aliases:
"Alias '{name}' is deprecated. See the module docs for more information".format(name=d['name']), if 'name' in d:
version=d.get('version'), date=d.get('date'), collection_name=d.get('collection_name')) self.deprecate(
"Alias '{name}' is deprecated. See the module docs for more information".format(name=d['name']),
version=d.get('version'), date=d.get('date'), collection_name=d.get('collection_name'))
# Since ansible-core 2.14.2, a message is present that can be directly printed:
if 'msg' in d:
self.deprecate(d['msg'], version=d.get('version'), date=d.get('date'), collection_name=d.get('collection_name'))
for w in self._validation_result._warnings: for w in self._validation_result._warnings:
self.warn('Both option {option} and its alias {alias} are set.'.format(option=w['option'], alias=w['alias'])) self.warn('Both option {option} and its alias {alias} are set.'.format(option=w['option'], alias=w['alias']))
@@ -444,7 +448,7 @@ class AnsibleActionModule(object):
} }
# Ignore, warn, or error when converting to a string. # Ignore, warn, or error when converting to a string.
allow_conversion = opts.get(self._string_conversion_action, True) allow_conversion = opts.get(C.STRING_CONVERSION_ACTION, True)
try: try:
return check_type_str(value, allow_conversion) return check_type_str(value, allow_conversion)
except TypeError: except TypeError:
@@ -459,10 +463,10 @@ class AnsibleActionModule(object):
from_msg = '{0}: {1!r}'.format(param, value) from_msg = '{0}: {1!r}'.format(param, value)
to_msg = '{0}: {1!r}'.format(param, to_text(value)) to_msg = '{0}: {1!r}'.format(param, to_text(value))
if self._string_conversion_action == 'error': if C.STRING_CONVERSION_ACTION == 'error':
msg = common_msg.capitalize() msg = common_msg.capitalize()
raise TypeError(to_native(msg)) raise TypeError(to_native(msg))
elif self._string_conversion_action == 'warn': elif C.STRING_CONVERSION_ACTION == 'warn':
msg = ('The value "{0}" (type {1.__class__.__name__}) was converted to "{2}" (type string). ' msg = ('The value "{0}" (type {1.__class__.__name__}) was converted to "{2}" (type string). '
'If this does not look like what you expect, {3}').format(from_msg, value, to_msg, common_msg) 'If this does not look like what you expect, {3}').format(from_msg, value, to_msg, common_msg)
self.warn(to_native(msg)) self.warn(to_native(msg))

8
simplified_bsd.txt Normal file
View File

@@ -0,0 +1,8 @@
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,4 @@
---
collections:
- community.general
- community.internal_test_tools

View File

@@ -158,7 +158,7 @@
method: get method: get
register: validation_result register: validation_result
loop: "{{ http01challenge.results | map(attribute='output_json') | list }}" loop: "{{ http01challenge.results | map(attribute='output_json') | list }}"
until: "validation_result.output_json.status != 'pending'" until: "validation_result.output_json.status not in ['pending', 'processing']"
retries: 20 retries: 20
delay: 1 delay: 1
- debug: var=validation_result - debug: var=validation_result

View File

@@ -107,7 +107,7 @@
- "'headers' in item" - "'headers' in item"
- "'output_text' in item" - "'output_text' in item"
- "'output_json' in item" - "'output_json' in item"
- item.output_json.status == 'pending' - item.output_json.status in ['pending', 'processing']
- item.output_json.type == 'http-01' - item.output_json.type == 'http-01'
- item.output_json.url == item.invocation.module_args.url - item.output_json.url == item.invocation.module_args.url
- "'token' in item.output_json" - "'token' in item.output_json"

View File

@@ -1,3 +1,4 @@
dependencies: dependencies:
- prepare_jinja2_compat
- setup_openssl - setup_openssl
- setup_remote_tmp_dir - setup_remote_tmp_dir

View File

@@ -0,0 +1,20 @@
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Generate CSR for {{ certificate.name }}
openssl_csr:
path: '{{ remote_tmp_dir }}/{{ certificate.name }}.csr'
privatekey_path: '{{ remote_tmp_dir }}/{{ certificate.name }}.key'
subject: '{{ certificate.subject }}'
useCommonNameForSAN: false
- name: Generate certificate for {{ certificate.name }}
x509_certificate:
path: '{{ remote_tmp_dir }}/{{ certificate.name }}.pem'
csr_path: '{{ remote_tmp_dir }}/{{ certificate.name }}.csr'
privatekey_path: '{{ remote_tmp_dir }}/{{ certificate.name }}.key'
provider: '{{ "selfsigned" if certificate.parent is not defined else "ownca" }}'
ownca_path: '{{ (remote_tmp_dir ~ "/" ~ certificate.parent ~ ".pem") if certificate.parent is defined else omit }}'
ownca_privatekey_path: '{{ (remote_tmp_dir ~ "/" ~ certificate.parent ~ ".key") if certificate.parent is defined else omit }}'

View File

@@ -0,0 +1,49 @@
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Create private keys
openssl_privatekey:
path: '{{ remote_tmp_dir }}/{{ item.name }}.key'
size: '{{ default_rsa_key_size_certifiates }}'
loop: '{{ certificates }}'
- name: Generate certificates
include_tasks: create-single-certificate.yml
loop: '{{ certificates }}'
loop_control:
loop_var: certificate
- name: Read certificates
slurp:
src: '{{ remote_tmp_dir }}/{{ item.name }}.pem'
loop: '{{ certificates }}'
register: certificates_read
- name: Store read certificates
set_fact:
read_certificates: >-
{{ certificates_read.results | map(attribute='content') | map('b64decode')
| zip(certificates | map(attribute='name'))
| list
| items2dict(key_name=1, value_name=0) }}
vars:
certificates:
- name: a-root
subject:
commonName: root common name
- name: b-intermediate
subject:
commonName: intermediate common name
parent: a-root
- name: c-intermediate
subject:
commonName: intermediate common name
parent: a-root
- name: d-leaf
subject:
commonName: leaf certificate
parent: b-intermediate

View File

@@ -0,0 +1,44 @@
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Case A => works
certificate_complete_chain:
input_chain: "{{ read_certificates['d-leaf'] }}"
intermediate_certificates:
- '{{ remote_tmp_dir }}/b-intermediate.pem'
root_certificates:
- '{{ remote_tmp_dir }}/a-root.pem'
- name: Case B => doesn't work, but this is expected
failed_when: no
register: caseb
certificate_complete_chain:
input_chain: "{{ read_certificates['d-leaf'] }}"
intermediate_certificates:
- '{{ remote_tmp_dir }}/c-intermediate.pem'
root_certificates:
- '{{ remote_tmp_dir }}/a-root.pem'
- name: Assert that case B failed
assert:
that: "'Cannot complete chain' in caseb.msg"
- name: Case C => works
certificate_complete_chain:
input_chain: "{{ read_certificates['d-leaf'] }}"
intermediate_certificates:
- '{{ remote_tmp_dir }}/c-intermediate.pem'
- '{{ remote_tmp_dir }}/b-intermediate.pem'
root_certificates:
- '{{ remote_tmp_dir }}/a-root.pem'
- name: Case D => works as well after PR 403
certificate_complete_chain:
input_chain: "{{ read_certificates['d-leaf'] }}"
intermediate_certificates:
- '{{ remote_tmp_dir }}/b-intermediate.pem'
- '{{ remote_tmp_dir }}/c-intermediate.pem'
root_certificates:
- '{{ remote_tmp_dir }}/a-root.pem'

View File

@@ -0,0 +1,144 @@
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Find root for cert 1 using directory
certificate_complete_chain:
input_chain: '{{ fullchain | trim }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert1_root
- name: Verify root for cert 1
assert:
that:
- cert1_root.complete_chain | join('') == (fullchain ~ root)
- cert1_root.root == root
vars:
fullchain: "{{ lookup('file', 'cert1-fullchain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert1-root.pem', rstrip=False) }}"
- block:
- name: Find rootchain for cert 1 using intermediate and root PEM
certificate_complete_chain:
input_chain: '{{ cert }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert1_rootchain
- name: Verify rootchain for cert 1
assert:
that:
- cert1_rootchain.complete_chain | join('') == (cert ~ chain ~ root)
- cert1_rootchain.chain[:-1] | join('') == chain
- cert1_rootchain.root == root
vars:
cert: "{{ lookup('file', 'cert1.pem', rstrip=False) }}"
chain: "{{ lookup('file', 'cert1-chain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert1-root.pem', rstrip=False) }}"
- block:
- name: Find root for cert 2 using directory
certificate_complete_chain:
input_chain: "{{ fullchain | trim }}"
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert2_root
- name: Verify root for cert 2
assert:
that:
- cert2_root.complete_chain | join('') == (fullchain ~ root)
- cert2_root.root == root
vars:
fullchain: "{{ lookup('file', 'cert2-fullchain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert2-root.pem', rstrip=False) }}"
- block:
- name: Find rootchain for cert 2 using intermediate and root PEM
certificate_complete_chain:
input_chain: '{{ cert }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain.complete_chain | join('') == (cert ~ chain ~ root)
- cert2_rootchain.chain[:-1] | join('') == chain
- cert2_rootchain.root == root
vars:
cert: "{{ lookup('file', 'cert2.pem', rstrip=False) }}"
chain: "{{ lookup('file', 'cert2-chain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert2-root.pem', rstrip=False) }}"
- block:
- name: Find alternate rootchain for cert 2 using intermediate and root PEM
certificate_complete_chain:
input_chain: '{{ cert }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-altchain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain_alt
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain_alt.complete_chain | join('') == (cert ~ chain ~ root)
- cert2_rootchain_alt.chain[:-1] | join('') == chain
- cert2_rootchain_alt.root == root
vars:
cert: "{{ lookup('file', 'cert2.pem', rstrip=False) }}"
chain: "{{ lookup('file', 'cert2-altchain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert2-altroot.pem', rstrip=False) }}"
- block:
- name: Find alternate rootchain for cert 2 when complete chain is already presented to the module
certificate_complete_chain:
input_chain: '{{ cert ~ chain ~ root }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_complete_chain
- name: Verify rootchain for cert 2
assert:
that:
- cert2_complete_chain.complete_chain | join('') == (cert ~ chain ~ root)
- cert2_complete_chain.chain == []
- cert2_complete_chain.root == root
vars:
cert: "{{ lookup('file', 'cert2.pem', rstrip=False) }}"
chain: "{{ lookup('file', 'cert2-altchain.pem', rstrip=False) }}"
root: "{{ lookup('file', 'cert2-altroot.pem', rstrip=False) }}"
- name: Check failure when no intermediate certificate can be found
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert2.pem", rstrip=True) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_no_intermediate
ignore_errors: true
- name: Verify failure
assert:
that:
- cert2_no_intermediate is failed
- "cert2_no_intermediate.msg.startswith('Cannot complete chain. Stuck at certificate ')"
- name: Check failure when infinite loop is found
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert2-fullchain.pem", rstrip=True) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
register: cert2_infinite_loop
ignore_errors: true
- name: Verify failure
assert:
that:
- cert2_infinite_loop is failed
- "cert2_infinite_loop.msg == 'Found cycle while building certificate chain'"

View File

@@ -4,6 +4,7 @@
#################################################################### ####################################################################
- block: - block:
- name: Make sure testhost directory exists - name: Make sure testhost directory exists
file: file:
path: '{{ remote_tmp_dir }}/files/' path: '{{ remote_tmp_dir }}/files/'
@@ -13,68 +14,14 @@
copy: copy:
src: '{{ role_path }}/files/' src: '{{ role_path }}/files/'
dest: '{{ remote_tmp_dir }}/files/' dest: '{{ remote_tmp_dir }}/files/'
- name: Find root for cert 1
certificate_complete_chain: - name: Run tests with copied certificates
input_chain: '{{ lookup("file", "cert1-fullchain.pem", rstrip=False) }}' import_tasks: existing.yml
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/' - name: Create more certificates
register: cert1_root import_tasks: create.yml
- name: Verify root for cert 1
assert: - name: Run tests with created certificates
that: import_tasks: created.yml
- cert1_root.complete_chain | join('') == (lookup('file', 'cert1.pem', rstrip=False) ~ lookup('file', 'cert1-chain.pem', rstrip=False) ~ lookup('file', 'cert1-root.pem', rstrip=False))
- cert1_root.root == lookup('file', 'cert1-root.pem', rstrip=False)
- name: Find rootchain for cert 1
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert1.pem", rstrip=False) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert1_rootchain
- name: Verify rootchain for cert 1
assert:
that:
- cert1_rootchain.complete_chain | join('') == (lookup('file', 'cert1.pem', rstrip=False) ~ lookup('file', 'cert1-chain.pem', rstrip=False) ~ lookup('file', 'cert1-root.pem', rstrip=False))
- cert1_rootchain.chain[:-1] | join('') == lookup('file', 'cert1-chain.pem', rstrip=False)
- cert1_rootchain.root == lookup('file', 'cert1-root.pem', rstrip=False)
- name: Find root for cert 2
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert2-fullchain.pem", rstrip=False) }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert2_root
- name: Verify root for cert 2
assert:
that:
- cert2_root.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-chain.pem', rstrip=False) ~ lookup('file', 'cert2-root.pem', rstrip=False))
- cert2_root.root == lookup('file', 'cert2-root.pem', rstrip=False)
- name: Find rootchain for cert 2
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert2.pem", rstrip=False) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-chain.pem', rstrip=False) ~ lookup('file', 'cert2-root.pem', rstrip=False))
- cert2_rootchain.chain[:-1] | join('') == lookup('file', 'cert2-chain.pem', rstrip=False)
- cert2_rootchain.root == lookup('file', 'cert2-root.pem', rstrip=False)
- name: Find alternate rootchain for cert 2
certificate_complete_chain:
input_chain: '{{ lookup("file", "cert2.pem", rstrip=True) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-altchain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain_alt
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain_alt.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-altchain.pem', rstrip=False) ~ lookup('file', 'cert2-altroot.pem', rstrip=False))
- cert2_rootchain_alt.chain[:-1] | join('') == lookup('file', 'cert2-altchain.pem', rstrip=False)
- cert2_rootchain_alt.root == lookup('file', 'cert2-altroot.pem', rstrip=False)
when: cryptography_version.stdout is version('1.5', '>=') when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -63,7 +63,11 @@
- result is not changed - result is not changed
- result is failed - result is failed
# We got the expected error message # We got the expected error message
- "'The handshake operation timed out' in result.msg or 'unknown protocol' in result.msg or 'wrong version number' in result.msg" - >-
'The handshake operation timed out' in result.msg
or 'unknown protocol' in result.msg
or 'wrong version number' in result.msg
or 'record layer failure' in result.msg
- name: Test timeout option - name: Test timeout option
get_certificate: get_certificate:

View File

@@ -6,6 +6,7 @@
keyfile: "{{ remote_tmp_dir }}/keyfile1" keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 256 keysize: 256
pbkdf: pbkdf:
algorithm: pbkdf2
iteration_count: 1000 iteration_count: 1000
become: yes become: yes
register: create_with_keysize register: create_with_keysize
@@ -16,6 +17,7 @@
keyfile: "{{ remote_tmp_dir }}/keyfile1" keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 256 keysize: 256
pbkdf: pbkdf:
algorithm: pbkdf2
iteration_count: 1000 iteration_count: 1000
become: yes become: yes
register: create_idem_with_keysize register: create_idem_with_keysize
@@ -26,6 +28,7 @@
keyfile: "{{ remote_tmp_dir }}/keyfile1" keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 512 keysize: 512
pbkdf: pbkdf:
algorithm: pbkdf2
iteration_count: 1000 iteration_count: 1000
become: yes become: yes
register: create_idem_with_diff_keysize register: create_idem_with_diff_keysize
@@ -36,6 +39,7 @@
keyfile: "{{ remote_tmp_dir }}/keyfile1" keyfile: "{{ remote_tmp_dir }}/keyfile1"
passphrase: "{{ cryptfile_passphrase1 }}" passphrase: "{{ cryptfile_passphrase1 }}"
pbkdf: pbkdf:
algorithm: pbkdf2
iteration_count: 1000 iteration_count: 1000
ignore_errors: yes ignore_errors: yes
become: yes become: yes

View File

@@ -86,6 +86,27 @@
regenerate: full_idempotence regenerate: full_idempotence
register: default_options register: default_options
- name: Generate host cert full_idempotence
openssh_cert:
type: host
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
valid_from: always
valid_to: forever
regenerate: full_idempotence
- name: Generate host cert full_idempotence again
openssh_cert:
type: host
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
valid_from: always
valid_to: forever
regenerate: full_idempotence
register: host_cert_full_idempotence
- name: Assert options results - name: Assert options results
assert: assert:
that: that:
@@ -95,6 +116,7 @@
- explicit_extension_after is not changed - explicit_extension_after is not changed
- explicit_extension_and_directive is changed - explicit_extension_and_directive is changed
- default_options is not changed - default_options is not changed
- host_cert_full_idempotence is not changed
- name: Remove certificate - name: Remove certificate
openssh_cert: openssh_cert:

View File

@@ -24,6 +24,7 @@
type: rsa type: rsa
size: 1024 size: 1024
backend: "{{ backend }}" backend: "{{ backend }}"
regenerate: "{{ item }}"
loop: "{{ regenerate_values }}" loop: "{{ regenerate_values }}"
- name: "({{ backend }}) Regenerate - setup password protected keys" - name: "({{ backend }}) Regenerate - setup password protected keys"
command: 'ssh-keygen -f {{ remote_tmp_dir }}/regenerate-b-{{ item }} -N {{ passphrase }}' command: 'ssh-keygen -f {{ remote_tmp_dir }}/regenerate-b-{{ item }} -N {{ passphrase }}'

View File

@@ -924,7 +924,6 @@
- CN=ca.example.com - CN=ca.example.com
reasons: reasons:
- certificate_hold - certificate_hold
- {}
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: crl_distribution_endpoints_1 register: crl_distribution_endpoints_1
@@ -947,7 +946,6 @@
- CN=ca.example.com - CN=ca.example.com
reasons: reasons:
- certificate_hold - certificate_hold
- {}
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: crl_distribution_endpoints_2 register: crl_distribution_endpoints_2
@@ -958,9 +956,7 @@
subject: subject:
commonName: www.ansible.com commonName: www.ansible.com
crl_distribution_points: crl_distribution_points:
- full_name: - crl_issuer:
- "URI:https://ca.example.com/revocations.crl"
crl_issuer:
- "URI:https://ca.example.com/" - "URI:https://ca.example.com/"
reasons: reasons:
- key_compromise - key_compromise

View File

@@ -8,7 +8,7 @@
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: result register: result
- name: "({{ select_crypto_backend }}) Check whether subject behaves as expected" - name: "({{ select_crypto_backend }}) Check whether subject and extensions behaves as expected"
assert: assert:
that: that:
- result.subject.organizationalUnitName == 'ACME Department' - result.subject.organizationalUnitName == 'ACME Department'
@@ -16,6 +16,21 @@
- "['organizationalUnitName', 'ACME Department'] in result.subject_ordered" - "['organizationalUnitName', 'ACME Department'] in result.subject_ordered"
- result.public_key_type == 'RSA' - result.public_key_type == 'RSA'
- result.public_key_data.size == default_rsa_key_size - result.public_key_data.size == default_rsa_key_size
# TLS Feature
- result.extensions_by_oid['1.3.6.1.5.5.7.1.24'].critical == false
- result.extensions_by_oid['1.3.6.1.5.5.7.1.24'].value == 'MAMCAQU='
# Key Usage
- result.extensions_by_oid['2.5.29.15'].critical == true
- result.extensions_by_oid['2.5.29.15'].value in ['AwMA/4A=', 'AwMH/4A=']
# Subject Alternative Names
- result.extensions_by_oid['2.5.29.17'].critical == false
- result.extensions_by_oid['2.5.29.17'].value == 'MGCCD3d3dy5hbnNpYmxlLmNvbYcEAQIDBIcQAAAAAAAAAAAAAAAAAAAAAYEQdGVzdEBleGFtcGxlLm9yZ4YjaHR0cHM6Ly9leGFtcGxlLm9yZy90ZXN0L2luZGV4Lmh0bWw='
# Basic Constraints
- result.extensions_by_oid['2.5.29.19'].critical == true
- result.extensions_by_oid['2.5.29.19'].value == 'MAYBAf8CARc='
# Extended Key Usage
- result.extensions_by_oid['2.5.29.37'].critical == false
- result.extensions_by_oid['2.5.29.37'].value == 'MHQGCCsGAQUFBwMBBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJBgRVHSUABggrBgEFBQcBAwYIKwYBBQUHAwoGCCsGAQUFBwMHBggrBgEFBQcBAg=='
- name: "({{ select_crypto_backend }}) Check SubjectKeyIdentifier and AuthorityKeyIdentifier" - name: "({{ select_crypto_backend }}) Check SubjectKeyIdentifier and AuthorityKeyIdentifier"
assert: assert:
@@ -24,6 +39,10 @@
- result.authority_key_identifier == "44:55:66:77" - result.authority_key_identifier == "44:55:66:77"
- result.authority_cert_issuer == expected_authority_cert_issuer - result.authority_cert_issuer == expected_authority_cert_issuer
- result.authority_cert_serial_number == 12345 - result.authority_cert_serial_number == 12345
# Subject Key Identifier
- result.extensions_by_oid['2.5.29.14'].critical == false
# Authority Key Identifier
- result.extensions_by_oid['2.5.29.35'].critical == false
vars: vars:
expected_authority_cert_issuer: expected_authority_cert_issuer:
- "DNS:ca.example.org" - "DNS:ca.example.org"

View File

@@ -45,6 +45,18 @@
return_content: true return_content: true
register: p12_standard_idempotency register: p12_standard_idempotency
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file again, idempotency (empty other_certificates)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
return_content: true
other_certificates: []
register: p12_standard_idempotency_no_certs
- name: "({{ select_crypto_backend }}) Read ansible.p12" - name: "({{ select_crypto_backend }}) Read ansible.p12"
slurp: slurp:
src: '{{ remote_tmp_dir }}/ansible.p12' src: '{{ remote_tmp_dir }}/ansible.p12'

View File

@@ -65,7 +65,10 @@
vars: vars:
select_crypto_backend: pyopenssl select_crypto_backend: pyopenssl
when: pyopenssl_version.stdout is version('0.15', '>=') when: >-
pyopenssl_version.stdout is version('0.15', '>=')
and
pyopenssl_version.stdout is version('23.3.0', '<')
- block: - block:
- name: Running tests with cryptography backend - name: Running tests with cryptography backend
@@ -75,4 +78,11 @@
when: cryptography_version.stdout is version('3.0', '>=') when: cryptography_version.stdout is version('3.0', '>=')
when: pyopenssl_version.stdout is version('0.15', '>=') or cryptography_version.stdout is version('3.0', '>=') when: >-
(
pyopenssl_version.stdout is version('0.15', '>=')
and
pyopenssl_version.stdout is version('23.3.0', '<')
)
or
cryptography_version.stdout is version('3.0', '>=')

View File

@@ -25,6 +25,7 @@
- p12_dumped is changed - p12_dumped is changed
- p12_standard_idempotency is not changed - p12_standard_idempotency is not changed
- p12_standard_idempotency_check is not changed - p12_standard_idempotency_check is not changed
- p12_standard_idempotency_no_certs is not changed
- p12_multiple_certs_idempotency is not changed - p12_multiple_certs_idempotency is not changed
- p12_dumped_idempotency is not changed - p12_dumped_idempotency is not changed
- p12_dumped_check_mode is not changed - p12_dumped_check_mode is not changed
@@ -83,4 +84,4 @@
- p12_empty is changed - p12_empty is changed
- p12_empty_idem is not changed - p12_empty_idem is not changed
- p12_empty_concat_idem is not changed - p12_empty_concat_idem is not changed
- empty_contents == (empty_expected_pyopenssl if select_crypto_backend == 'pyopenssl' else empty_expected_cryptography) - (empty_contents == empty_expected_cryptography) or (empty_contents == empty_expected_pyopenssl and select_crypto_backend == 'pyopenssl')

View File

@@ -303,11 +303,18 @@
size: '{{ default_rsa_key_size }}' size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_mode_1 register: privatekey_mode_1
- name: "({{ select_crypto_backend }}) Stat for privatekey_mode" - name: "({{ select_crypto_backend }}) Stat for privatekey_mode"
stat: stat:
path: '{{ remote_tmp_dir }}/privatekey_mode.pem' path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
register: privatekey_mode_1_stat register: privatekey_mode_1_stat
- name: "({{ select_crypto_backend }}) Collect file information"
community.internal_test_tools.files_collect:
files:
- path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
register: privatekey_mode_1_fileinfo
- name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, idempotency)" - name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, idempotency)"
openssl_privatekey: openssl_privatekey:
path: '{{ remote_tmp_dir }}/privatekey_mode.pem' path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
@@ -316,13 +323,6 @@
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_mode_2 register: privatekey_mode_2
- name: Make sure that mtime actually changes.
# The "privatekey_mode_1_stat.stat.mtime != privatekey_mode_3_stat.stat.mtime" test should be
# changed to compare content instead of mtime. On macOS 10.15, mtime resolution is one second,
# and the machine (VM) is fast enough that both modifications can happen in the same second.
pause:
seconds: 1
- name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, force)" - name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, force)"
openssl_privatekey: openssl_privatekey:
path: '{{ remote_tmp_dir }}/privatekey_mode.pem' path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
@@ -331,11 +331,17 @@
size: '{{ default_rsa_key_size }}' size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}' select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_mode_3 register: privatekey_mode_3
- name: "({{ select_crypto_backend }}) Stat for privatekey_mode" - name: "({{ select_crypto_backend }}) Stat for privatekey_mode"
stat: stat:
path: '{{ remote_tmp_dir }}/privatekey_mode.pem' path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
register: privatekey_mode_3_stat register: privatekey_mode_3_stat
- name: "({{ select_crypto_backend }}) Make sure that file changed"
community.internal_test_tools.files_diff:
state: '{{ privatekey_mode_1_fileinfo }}'
register: privatekey_mode_3_file_change
- block: - block:
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format" - name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format"
openssl_privatekey: openssl_privatekey:

View File

@@ -186,7 +186,7 @@
- privatekey_mode_2 is not changed - privatekey_mode_2 is not changed
- privatekey_mode_3 is changed - privatekey_mode_3 is changed
- privatekey_mode_3_stat.stat.mode == '0400' - privatekey_mode_3_stat.stat.mode == '0400'
- privatekey_mode_1_stat.stat.mtime != privatekey_mode_3_stat.stat.mtime - privatekey_mode_3_file_change is changed
- name: "({{ select_crypto_backend }}) Validate format 1" - name: "({{ select_crypto_backend }}) Validate format 1"
assert: assert:

View File

@@ -71,7 +71,8 @@
- name: Compare results - name: Compare results
assert: assert:
that: that:
- ' (pyopenssl_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict) - >-
== (cryptography_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict)' (pyopenssl_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | rejectattr("key", "equalto", "key_is_consistent") | list | items2dict)
== (cryptography_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | rejectattr("key", "equalto", "key_is_consistent") | list | items2dict)
loop: "{{ pyopenssl_info_results.keys() | intersect(cryptography_info_results.keys()) | list }}" loop: "{{ pyopenssl_info_results.keys() | intersect(cryptography_info_results.keys()) | list }}"
when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.2.3', '>=') when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.2.3', '>=')

View File

@@ -39,7 +39,7 @@
- name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format (assert)" - name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format (assert)"
assert: assert:
that: that:
- privatekey_publickey.stdout == '{{ publickey.content|b64decode }}' - privatekey_publickey.stdout == publickey.content | b64decode
when: select_crypto_backend == 'cryptography' and cryptography_version.stdout is version('1.4.0', '>=') when: select_crypto_backend == 'cryptography' and cryptography_version.stdout is version('1.4.0', '>=')
- name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format - test idempotence (issue 33256)" - name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format - test idempotence (issue 33256)"

View File

@@ -4,6 +4,7 @@ default_rsa_key_size_certifiates: >-
{{ {{
2048 if 2048 if
(ansible_os_family == "RedHat" and ansible_facts.distribution_major_version | int >= 8) or (ansible_os_family == "RedHat" and ansible_facts.distribution_major_version | int >= 8) or
(ansible_distribution == "Ubuntu" and ansible_facts.distribution_major_version | int >= 20) (ansible_distribution == "Ubuntu" and ansible_facts.distribution_major_version | int >= 20) or
(ansible_os_family == "Darwin" and ansible_facts.distribution_major_version | int >= 12)
else 1024 else 1024
}} }}

View File

@@ -32,13 +32,19 @@ system_python_version_data:
- '3.8' - '3.8'
'11.1': '11.1':
- '3.9' - '3.9'
'12.0':
- '3.10'
FreeBSD: FreeBSD:
'12.1': '12.1':
- '3.6' - '3.6'
'12.2': '12.2':
- '3.7' - '3.7'
'12.3':
- '3.8'
'13.0': '13.0':
- '3.7' - '3.7'
'13.1':
- '3.8'
RedHat: RedHat:
'7': '7':
- '2.7' - '2.7'
@@ -55,3 +61,6 @@ cannot_upgrade_cryptography:
- '3.8' # on the VMs in CI, system packages are used for this version as well - '3.8' # on the VMs in CI, system packages are used for this version as well
'13.0': '13.0':
- '3.8' # on the VMs in CI, system packages are used for this version as well - '3.8' # on the VMs in CI, system packages are used for this version as well
Ubuntu:
'18':
- '3.9' # this is the default container for ansible-core 2.12; upgrading cryptography wrecks pyOpenSSL

View File

@@ -1,7 +1,18 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: create ~/tmp
file:
path: '~/tmp'
state: directory
- name: create temporary directory - name: create temporary directory
tempfile: tempfile:
state: directory state: directory
suffix: .test suffix: .test
path: '~/tmp'
register: remote_tmp_dir register: remote_tmp_dir
notify: notify:
- delete temporary directory - delete temporary directory

Some files were not shown because too many files have changed in this diff Show More