Skip to content

Fix load_certificate/load_private_key ignoring explicit format argument#1954

Merged
oroulet merged 1 commit intoFreeOpcUa:masterfrom
Lidang-Jiang:fix/load-certificate-format-argument
Apr 5, 2026
Merged

Fix load_certificate/load_private_key ignoring explicit format argument#1954
oroulet merged 1 commit intoFreeOpcUa:masterfrom
Lidang-Jiang:fix/load-certificate-format-argument

Conversation

@Lidang-Jiang
Copy link
Copy Markdown
Contributor

Summary

Changes

  • asyncua/crypto/uacrypto.py: Add _is_pem_format() helper, refactor both load_certificate and load_private_key to use it
  • tests/test_gen_certificates.py: Add 4 regression tests covering explicit format override and format inference

Root Cause

The condition if ext == ".pem" or extension == "pem" checked the file extension (ext) before the explicit extension parameter, so ext == ".pem" would short-circuit even when extension="der" was explicitly passed.

Fix

When extension is explicitly provided (not None), use it exclusively. Only infer from the file path suffix when extension is None.

Before (bug reproduction)
=== Test 1: load_certificate(cert.pem, extension='der') ===
FAIL: ValueError: Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. MalformedFraming

=== Test 2: load_private_key(key.pem, extension='der') ===
FAIL: ValueError: Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. MalformedFraming

=== Test 3: load_certificate(cert.pem, extension=None) — expected failure ===
EXPECTED FAIL: ValueError: Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. MalformedFraming
After (fix verified)
=== Test 1: load_certificate(cert.pem, extension='der') ===
OK: Loaded certificate: <Name(CN=Test)>

=== Test 2: load_private_key(key.pem, extension='der') ===
OK: Loaded private key: 2048 bits

=== Test 3: load_certificate(cert.pem, extension=None) — expected failure ===
EXPECTED FAIL: ValueError: Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. MalformedFraming
Test output
$ pytest tests/test_gen_certificates.py -v

tests/test_gen_certificates.py::test_create_self_signed_app_certificate PASSED [ 12%]
tests/test_gen_certificates.py::test_app_create_certificate_signing_request PASSED [ 25%]
tests/test_gen_certificates.py::test_app_sign_certificate_request PASSED [ 37%]
tests/test_gen_certificates.py::test_generate_load_private_key_pem PASSED [ 50%]
tests/test_gen_certificates.py::test_load_certificate_explicit_der_with_pem_extension PASSED [ 62%]
tests/test_gen_certificates.py::test_load_private_key_explicit_der_with_pem_extension PASSED [ 75%]
tests/test_gen_certificates.py::test_load_certificate_explicit_pem_with_der_extension PASSED [ 87%]
tests/test_gen_certificates.py::test_load_certificate_infers_from_file_extension PASSED [100%]

============================== 8 passed in 0.31s ===============================

Full regression (110 passed, 3 skipped):

$ pytest tests/test_cert_chain.py tests/test_gen_certificates.py tests/test_crypto_connect.py tests/test_server.py tests/test_client.py -v
================== 110 passed, 3 skipped in 133.21s (0:02:13) ==================

Test plan

  • DER-encoded certificate with .pem extension loads correctly with extension="der"
  • DER-encoded private key with .pem extension loads correctly with extension="der"
  • PEM-encoded certificate with .der extension loads correctly with extension="pem"
  • Format inference from file extension still works when no explicit extension given
  • Existing tests pass (no regression)

When an explicit `extension` parameter is provided (e.g., extension="der"),
it should take precedence over the file extension inferred from the path.
Previously, a file named "cert.pem" would always be loaded as PEM format,
even when extension="der" was explicitly passed.

Extract a shared `_is_pem_format()` helper that checks the explicit
extension first, falling back to file extension inference only when
no explicit format is given.

Closes FreeOpcUa#1927

Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
@oroulet oroulet merged commit 2889b9b into FreeOpcUa:master Apr 5, 2026
6 checks passed
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.

load_certificate ignores format argument and infers format from file extension

2 participants