Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openssl_pkcs12: Add support for certificate_content and other_certificates_content #848

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

apollo13
Copy link
Contributor

@apollo13 apollo13 commented Feb 17, 2025

Fixes #847

SUMMARY
ISSUE TYPE
  • Feature Pull Request
COMPONENT NAME

openssl_pkcs21

Copy link

github-actions bot commented Feb 17, 2025

Docs Build 📝

Thank you for contribution!✨

The docs for this PR have been published here:
https://ansible-collections.github.io/community.crypto/pr/848

You can compare to the docs for the main branch here:
https://ansible-collections.github.io/community.crypto/branch/main

The docsite for this PR is also available for download as an artifact from this run:
https://github.com/ansible-collections/community.crypto/actions/runs/13385645517

File changes:

Click to see the diff comparison.

NOTE: only file modifications are shown here. New and deleted files are excluded.
See the file list and check the published docs to see those files.

diff --git a/home/runner/work/community.crypto/community.crypto/docsbuild/base/openssl_pkcs12_module.html b/home/runner/work/community.crypto/community.crypto/docsbuild/head/openssl_pkcs12_module.html
index a80ac0a..4613080 100644
--- a/home/runner/work/community.crypto/community.crypto/docsbuild/base/openssl_pkcs12_module.html
+++ b/home/runner/work/community.crypto/community.crypto/docsbuild/head/openssl_pkcs12_module.html
@@ -261,14 +261,24 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 </div></td>
 </tr>
 <tr class="row-odd"><td><div class="ansible-option-cell">
+<div class="ansibleOptionAnchor" id="parameter-certificate_content"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-certificate-content"><strong>certificate_content</strong></p>
+<a class="ansibleOptionLink" href="#parameter-certificate_content" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">string</span></p>
+<p><em class="ansible-option-versionadded">added in community.crypto 2.26.0</em></p>
+</div></td>
+<td><div class="ansible-option-cell"><p>Content of the certificate file in PEM format.</p>
+<p>Mutually exclusive with <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-certificate-path"><span class="std std-ref"><span class="pre">certificate_path</span></span></a></strong></code>.</p>
+</div></td>
+</tr>
+<tr class="row-even"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-certificate_path"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-certificate-path"><strong>certificate_path</strong></p>
 <a class="ansibleOptionLink" href="#parameter-certificate_path" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">path</span></p>
 </div></td>
 <td><div class="ansible-option-cell"><p>The path to read certificates and private keys from.</p>
 <p>Must be in PEM format.</p>
+<p>Mutually exclusive with <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-certificate-content"><span class="std std-ref"><span class="pre">certificate_content</span></span></a></strong></code>.</p>
 </div></td>
 </tr>
-<tr class="row-even"><td><div class="ansible-option-cell">
+<tr class="row-odd"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-encryption_level"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-encryption-level"><strong>encryption_level</strong></p>
 <a class="ansibleOptionLink" href="#parameter-encryption_level" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">string</span></p>
 <p><em class="ansible-option-versionadded">added in community.crypto 2.8.0</em></p>
@@ -284,7 +294,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 </ul>
 </div></td>
 </tr>
-<tr class="row-odd"><td><div class="ansible-option-cell">
+<tr class="row-even"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-force"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-force"><strong>force</strong></p>
 <a class="ansibleOptionLink" href="#parameter-force" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">boolean</span></p>
 </div></td>
@@ -296,7 +306,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 </ul>
 </div></td>
 </tr>
-<tr class="row-even"><td><div class="ansible-option-cell">
+<tr class="row-odd"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-friendly_name"></div>
 <div class="ansibleOptionAnchor" id="parameter-name"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-name"><span id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-friendly-name"></span><strong>friendly_name</strong></p>
 <a class="ansibleOptionLink" href="#parameter-friendly_name" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-aliases">aliases: name</span></p>
@@ -305,7 +315,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 <td><div class="ansible-option-cell"><p>Specifies the friendly name for the certificate and private key.</p>
 </div></td>
 </tr>
-<tr class="row-odd"><td><div class="ansible-option-cell">
+<tr class="row-even"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-group"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-group"><strong>group</strong></p>
 <a class="ansibleOptionLink" href="#parameter-group" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">string</span></p>
 </div></td>
@@ -313,7 +323,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 <p>When left unspecified, it uses the current group of the current user unless you are root, in which case it can preserve the previous ownership.</p>
 </div></td>
 </tr>
-<tr class="row-even"><td><div class="ansible-option-cell">
+<tr class="row-odd"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-iter_size"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-iter-size"><strong>iter_size</strong></p>
 <a class="ansibleOptionLink" href="#parameter-iter_size" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">integer</span></p>
 </div></td>
@@ -323,7 +333,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 <p>When using it, the default is <code class="ansible-value docutils literal notranslate"><span class="pre">2048</span></code> for <code class="docutils literal notranslate"><span class="pre">pyopenssl</span></code> and <code class="ansible-value docutils literal notranslate"><span class="pre">50000</span></code> for <code class="docutils literal notranslate"><span class="pre">cryptography</span></code>.</p>
 </div></td>
 </tr>
-<tr class="row-odd"><td><div class="ansible-option-cell">
+<tr class="row-even"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-maciter_size"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-maciter-size"><strong>maciter_size</strong></p>
 <a class="ansibleOptionLink" href="#parameter-maciter_size" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">integer</span></p>
 </div></td>
@@ -332,7 +342,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 <p>This is only used by the <code class="docutils literal notranslate"><span class="pre">pyopenssl</span></code> backend. When using it, the default is <code class="ansible-value docutils literal notranslate"><span class="pre">1</span></code>.</p>
 </div></td>
 </tr>
-<tr class="row-even"><td><div class="ansible-option-cell">
+<tr class="row-odd"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-mode"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-mode"><strong>mode</strong></p>
 <a class="ansibleOptionLink" href="#parameter-mode" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">any</span></p>
 </div></td>
@@ -345,7 +355,7 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 <p>Specifying <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-mode"><span class="std std-ref"><span class="pre">mode</span></span></a></strong></code> is the best way to ensure filesystem objects are created with the correct permissions. See CVE-2020-1736 for further details.</p>
 </div></td>
 </tr>
-<tr class="row-odd"><td><div class="ansible-option-cell">
+<tr class="row-even"><td><div class="ansible-option-cell">
 <div class="ansibleOptionAnchor" id="parameter-other_certificates"></div>
 <div class="ansibleOptionAnchor" id="parameter-ca_certificates"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-other-certificates"><span id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-ca-certificates"></span><strong>other_certificates</strong></p>
 <a class="ansibleOptionLink" href="#parameter-other_certificates" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-aliases">aliases: ca_certificates</span></p>
@@ -353,6 +363,17 @@ see <a class="reference internal" href="#ansible-collections-community-crypto-op
 </div></td>
 <td><div class="ansible-option-cell"><p>List of other certificates to include. Pre Ansible 2.8 this parameter was called <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-ca-certificates"><span class="std std-ref"><span class="pre">ca_certificates</span></span></a></strong></code>.</p>
 <p>Assumes there is one PEM-encoded certificate per file. If a file contains multiple PEM certificates, set <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-other-certificates-parse-all"><span class="std std-ref"><span class="pre">other_certificates_parse_all</span></span></a></strong></code> to <code class="ansible-value docutils literal notranslate"><span class="pre">true</span></code>.</p>
+<p>Mutually exclusive with <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-other-certificates-content"><span class="std std-ref"><span class="pre">other_certificates_content</span></span></a></strong></code>.</p>
+</div></td>
+</tr>
+<tr class="row-odd"><td><div class="ansible-option-cell">
+<div class="ansibleOptionAnchor" id="parameter-other_certificates_content"></div><p class="ansible-option-title" id="ansible-collections-community-crypto-openssl-pkcs12-module-parameter-other-certificates-content"><strong>other_certificates_content</strong></p>
+<a class="ansibleOptionLink" href="#parameter-other_certificates_content" title="Permalink to this option"></a><p class="ansible-option-type-line"><span class="ansible-option-type">list</span> / <span class="ansible-option-elements">elements=string</span></p>
+<p><em class="ansible-option-versionadded">added in community.crypto 2.26.0</em></p>
+</div></td>
+<td><div class="ansible-option-cell"><p>List of other certificates to include.</p>
+<p>Assumes there is one PEM-encoded certificate per item.</p>
+<p>Mutually exclusive with <code class="ansible-option docutils literal notranslate"><strong><a class="reference internal" href="#ansible-collections-community-crypto-openssl-pkcs12-module-parameter-other-certificates"><span class="std std-ref"><span class="pre">other_certificates</span></span></a></strong></code>.</p>
 </div></td>
 </tr>
 <tr class="row-even"><td><div class="ansible-option-cell">

@apollo13 apollo13 force-pushed the fb-pksc12-content branch 7 times, most recently from 30cc08f to c1cc42f Compare February 17, 2025 09:11
@@ -402,6 +426,10 @@ def __init__(self, module, backend, iter_size_default=2048):
self.other_certificates = [
load_certificate(other_cert, backend=self.backend) for other_cert in self.other_certificates
]
elif self.other_certificates_content:
self.other_certificates = [
load_certificate(None, content=to_bytes(other_cert), backend=self.backend) for other_cert in self.other_certificates_content
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if load_certificate should do a to_bytes instead.

@apollo13 apollo13 force-pushed the fb-pksc12-content branch 3 times, most recently from 35aa142 to b9de820 Compare February 17, 2025 09:40
@@ -4,6 +4,51 @@
# SPDX-License-Identifier: GPL-3.0-or-later

- block:
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file from contents"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added this minimal test because the other tests basically test the new behavior as well (since everything is basically redirect to content now). What worries me a bit about the tests is that I don't understand how for instance

name: "({{ select_crypto_backend }}) Generate PKCS#12 file with multiple certs and passphrase, again (idempotency)"

is actually checking idempotency. It does register p12_multiple_certs_idempotency but never checks that the result is unchanged (cannot find that the variable is used at all)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check tests/integration/targets/openssl_pkcs12/tests/validate.yml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outch, that is embarrassing, I saw some asserts in impl.yml like:

  - name: "({{ select_crypto_backend }}) Validate PKCS#12"
    assert:
      that:
      - p12_standard.pkcs12 == ansible_p12_content.content
      - p12_standard_idempotency.pkcs12 == p12_standard.pkcs12

and assumed the tests where inline. Sorry for that!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using tests/validate.yml for assertions is something that community.crypto (resp. its tests) have been doing for a loong time. I can't say I like it too much, but also not that little that I'd change all of them ;-) Some newer modules simply have all tests in tasks/main.yml (or some files in tasks/)...

@apollo13 apollo13 marked this pull request as ready for review February 17, 2025 09:44
elif self.other_certificates_content:
self.other_certificates = [
load_certificate(None, content=to_bytes(other_cert), backend=self.backend) for other_cert in self.other_certificates_content
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing support for other_certificates_parse_all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this when writing the code, does it actually make sense to have for the content variant? Wouldn't be hard to add but probably not common?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea... One possible use case would be loading the CA file (containing a list of PEMs) on the controller and running the module on the remote. If you can use that option here as well, you don't need to write the file to disk on the remote first.

@apollo13 apollo13 marked this pull request as draft February 18, 2025 07:46
@apollo13
Copy link
Contributor Author

Will add some further tests later on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support cert(s) from content in the pkcs12 module
2 participants