Skip to content

feat: POC of PQC negotiation with candlepin server#3713

Draft
jirihnidek wants to merge 2 commits intomainfrom
jhnidek/pqc_poc
Draft

feat: POC of PQC negotiation with candlepin server#3713
jirihnidek wants to merge 2 commits intomainfrom
jhnidek/pqc_poc

Conversation

@jirihnidek
Copy link
Contributor

@jirihnidek jirihnidek commented Mar 2, 2026

  • Introduced new configuration option certificate_signatures. It can have two possible options: "legacy" and "current". Default value is "legacy". When an user set the value to "current", then it opts-in using PQC for consumer and entitlement certificates and thus related connections.
  • When the certificate_signatures option is set, then client (subscription-manager or rhsm.service) adds the list of supported public key algorithms to the JSON object that is sent during "register" (POST /consumers?owner=$OWNER)
  • Fixed unit tests

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 2, 2026

Reviewer's Guide

Implements client-side PQC negotiation by adding a configurable certificate_signatures mode, wiring supported public key algorithms into the consumer registration request, updating defaults and rhsm.conf, and fixing impacted tests plus a flaky file monitor assertion.

Sequence diagram for PQC-aware consumer registration

sequenceDiagram
    actor User
    participant SubscriptionManager as RhsmlibServicesRegister
    participant Config as RhsmConfig
    participant PQC as SubscriptionManagerPqc
    participant Conn as RhsmConnection
    participant Candlepin as CandlepinServer

    User->>SubscriptionManager: register(options)
    SubscriptionManager->>Config: get_config_parser()
    Config-->>SubscriptionManager: config
    SubscriptionManager->>Config: get rhsm.certificate_signatures
    Config-->>SubscriptionManager: certificate_signatures

    alt certificate_signatures == current
        SubscriptionManager->>PQC: get_public_key_algorithms()
        PQC-->>SubscriptionManager: crypto_algorithms: List[str]
    else certificate_signatures == legacy
        SubscriptionManager->>SubscriptionManager: Use legacy certificate algorithms
        Note over SubscriptionManager: crypto_algorithms = None
    else unknown value
        SubscriptionManager->>SubscriptionManager: Log warning
        Note over SubscriptionManager: crypto_algorithms = None
    end

    SubscriptionManager->>Conn: registerConsumer(..., crypto_algorithms)
    Conn->>Conn: Build headers and params
    alt crypto_algorithms is not None
        Conn->>Conn: params[cryptographicAlgorithms] = crypto_algorithms
    end
    Conn->>Candlepin: POST /consumers
    Candlepin-->>Conn: Consumer JSON
    Conn-->>SubscriptionManager: Consumer JSON
    SubscriptionManager-->>User: Registration result
Loading

Class diagram for PQC negotiation and configuration changes

classDiagram
    class RhsmlibServicesRegister {
        +register(options)
    }

    class RhsmConnection {
        +registerConsumer(name, type, facts, hostname, uuid, organization, environment, service_level, usage, jwt_token, crypto_algorithms: List~str~)
    }

    class SubscriptionManagerPqc {
        +run(cmd, shell, cwd)
        +get_public_key_algorithms()
        +__smoke_test__()
    }

    class RhsmConfigDefaults {
        +RHSM_DEFAULTS
        +certificate_signatures = "legacy"
    }

    class RhsmConfFile {
        +certificate_signatures = current
    }

    RhsmlibServicesRegister --> RhsmConfigDefaults : reads_defaults
    RhsmlibServicesRegister --> RhsmConfFile : reads_runtime_value
    RhsmlibServicesRegister --> SubscriptionManagerPqc : uses_get_public_key_algorithms
    RhsmlibServicesRegister --> RhsmConnection : calls_registerConsumer
    RhsmConnection --> CandlepinServer : POST_consumers

    class CandlepinServer {
        +createConsumer(cryptographicAlgorithms: List~str~)
    }
Loading

File-Level Changes

Change Details Files
Add PQC-capable crypto algorithm discovery and wire it into consumer registration when enabled by configuration.
  • Introduce helper module that shells out to openssl list -public-key-algorithms and parses non-legacy OID identifiers into a list
  • Load new rhsm.certificate_signatures config option during register, compute crypto_algorithms list in 'current' mode, and log behavior for 'current', 'legacy', and unknown values
  • Pass crypto_algorithms through to the connection.registerConsumer call and include it as cryptographicAlgorithms in registration parameters when present
src/subscription_manager/pqc.py
src/rhsmlib/services/register.py
src/rhsm/connection.py
Define and document the new certificate_signatures configuration with sensible defaults.
  • Add certificate_signatures key with default 'legacy' into RHSM default configuration
  • Document the option in rhsm.conf and set its sample value to 'current' for POC usage
src/rhsm/config.py
etc-conf/rhsm.conf
Update and stabilize tests to reflect the new registration argument and relax a brittle file monitor assertion.
  • Extend register unit tests to expect the new crypto_algorithms argument (None in existing scenarios)
  • Relax a file monitor test to assert a minimum notification count instead of an exact value to reduce flakiness
test/rhsmlib/services/test_register.py
test/rhsmlib/test_file_monitor.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@jirihnidek
Copy link
Contributor Author

jirihnidek commented Mar 2, 2026

It adds following to the body of HTTP request on Fedora 43:

"cryptographicAlgorithms": [
    "1.2.840.113549.1.1.1",
    "1.2.840.113549.1.3.1",
    "1.2.840.10040.4.1",
    "1.2.840.10045.2.1",
    "1.2.840.113549.1.1.10",
    "1.2.840.10046.2.1",
    "1.3.101.110",
    "1.3.101.111",
    "1.3.101.112",
    "1.3.101.113",
    "2.16.840.1.101.3.4.3.17",
    "2.16.840.1.101.3.4.3.18",
    "2.16.840.1.101.3.4.3.19",
    "1.3.6.1.4.1.11591.4.11",
    "2.16.840.1.101.3.4.4.1",
    "2.16.840.1.101.3.4.4.2",
    "2.16.840.1.101.3.4.4.3",
    "2.16.840.1.101.3.4.3.20",
    "2.16.840.1.101.3.4.3.21",
    "2.16.840.1.101.3.4.3.22",
    "2.16.840.1.101.3.4.3.23",
    "2.16.840.1.101.3.4.3.24",
    "2.16.840.1.101.3.4.3.25",
    "2.16.840.1.101.3.4.3.26",
    "2.16.840.1.101.3.4.3.27",
    "2.16.840.1.101.3.4.3.28",
    "2.16.840.1.101.3.4.3.29",
    "2.16.840.1.101.3.4.3.30",
    "2.16.840.1.101.3.4.3.31"
]

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

New security issues found

@github-actions
Copy link

github-actions bot commented Mar 2, 2026

Coverage

Coverage (computed on Fedora latest) •
FileStmtsMissBranchBrPartCoverMissing
rhsm
   config.py178954694%157, 170, 182–183, 232, 395–396, 402, 411
   connection.py103448639625053%48–49, 53, 55–56, 81, 95, 144–148, 281, 312, 378–383, 387–396, 457, 459, 565, 568, 575–581, 586, 646, 681–685, 687, 691–692, 703, 730, 733–734, 736–737, 739, 747–748, 751–755, 759–762, 765–768, 770–771, 773, 775, 777, 788–792, 796, 800, 802–803, 822, 825, 829–830, 835, 838–839, 854, 858, 860–861, 888–889, 891, 894, 899–902, 905–906, 908, 910–914, 916–917, 920–927, 929–939, 941, 943–944, 955–957, 959–961, 963–965, 967–969, 971, 974–980, 982–983, 985–986, 988, 999–1001, 1003–1004, 1006–1008, 1010, 1022–1025, 1030, 1093–1094, 1096–1101, 1103, 1108–1112, 1118–1121, 1123–1128, 1132–1137, 1144, 1181, 1183, 1188, 1199, 1208–1211, 1215, 1217–1219, 1223–1224, 1226–1233, 1235, 1237, 1240–1247, 1250–1254, 1257–1261, 1263, 1270, 1272, 1279, 1286, 1338, 1355–1358, 1382, 1404, 1434, 1439, 1442, 1445–1446, 1451, 1454, 1459, 1462, 1505–1509, 1516–1517, 1519, 1528–1529, 1531, 1548, 1561–1563, 1566, 1577, 1582, 1586, 1616–1618, 1623–1624, 1626–1627, 1629–1630, 1632–1651, 1653–1655, 1657–1658, 1660–1671, 1673, 1690–1692, 1694–1696, 1698–1700, 1705, 1710–1712, 1717, 1744, 1775–1801, 1806–1807, 1809–1811, 1814–1815, 1818–1819, 1822–1823, 1842–1843, 1852–1853, 1863–1864, 1871–1872, 1878–1879, 1885–1886, 1906–1907, 1923–1929, 1931, 1939–1940, 1978, 1980–1982, 1984, 1986, 1989, 1991–2004, 2006–2007, 2016–2018, 2030–2031, 2040–2041, 2043, 2045–2047, 2054–2056, 2065–2066, 2068–2070, 2078–2079, 2090, 2092–2093, 2095, 2097–2100, 2102–2104, 2107, 2109, 2116–2117, 2124–2125, 2135–2136, 2146–2149, 2156–2159, 2170
rhsmlib/services
   register.py12422561682%71, 84–85, 87–88, 90–91, 93–94, 123–124, 128, 140, 196, 231, 262, 264, 276, 285, 304, 311, 313
subscription_manager
   pqc.py5950282715%16, 26–27, 38–45, 48–51, 57–71, 74–78, 85–88, 95–100, 102–105, 108
TOTAL1729345114778181073% 

Tests Skipped Failures Errors Time
2443 14 💤 0 ❌ 0 🔥 22.535s ⏱️

Copy link
Contributor

@m-horky m-horky left a comment

Choose a reason for hiding this comment

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

Overall I like the patch. I left a few notes.

Copy link
Contributor

Choose a reason for hiding this comment

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

This feels unrelated, could you move it to a separate commit? I know you are mentioning it in the git message, but I'd like to make it explicit it is not related to PQC.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, this is only POC. I will do it better in real PR.

@jirihnidek
Copy link
Contributor Author

I really did not ask for closing this PR!

@jirihnidek
Copy link
Contributor Author

I did not want to close the PR.

@jirihnidek
Copy link
Contributor Author

I want to re-open this PR.

@jirihnidek jirihnidek reopened this Mar 2, 2026
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

New security issues found

Comment on lines +15 to +23
proc = subprocess.Popen(
cmd,
shell=shell,
cwd=cwd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
errors="surrogateescape",
)
Copy link

Choose a reason for hiding this comment

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

security (python.lang.security.audit.dangerous-subprocess-use-audit): Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

Source: opengrep

@jirihnidek
Copy link
Contributor Author

When union of public key an signature algorithms is used, then the list is little bit longer:

"cryptographicAlgorithms": [
    "2.16.840.1.101.3.4.3.9",
    "2.16.840.1.101.3.4.3.30",
    "2.16.840.1.101.3.4.4.2",
    "1.2.840.10045.4.3.2",
    "2.16.840.1.101.3.4.3.28",
    "1.2.840.113549.1.1.5",
    "1.2.840.113549.1.3.1",
    "2.16.840.1.101.3.4.3.29",
    "2.16.840.1.101.3.4.3.15",
    "2.16.840.1.101.3.4.3.18",
    "1.2.840.113549.1.1.16",
    "2.16.840.1.101.3.4.3.20",
    "1.3.36.3.3.1.2",
    "2.16.840.1.101.3.4.3.1",
    "2.16.840.1.101.3.4.3.19",
    "2.16.840.1.101.3.4.4.1",
    "1.2.840.10040.4.1",
    "1.2.840.10045.4.3.4",
    "1.2.840.113549.1.1.1",
    "1.2.840.113549.1.1.13",
    "1.2.840.1.101.3.4.3.3",
    "2.16.840.1.101.3.4.3.25",
    "1.3.101.110",
    "2.16.840.1.101.3.4.3.23",
    "1.2.840.113549.1.1.11",
    "1.2.840.10040.4.3",
    "1.2.840.1.101.3.4.3.4",
    "2.16.840.1.101.3.4.3.5",
    "2.16.840.1.101.3.4.4.3",
    "1.2.840.10045.2.1",
    "1.2.840.113549.1.1.14",
    "1.3.6.1.4.1.11591.4.11",
    "2.16.840.1.101.3.4.3.22",
    "1.2.840.113549.1.1.15",
    "2.16.840.1.101.3.4.3.2",
    "1.2.840.10045.4.3.1",
    "1.3.101.113",
    "2.16.840.1.101.3.4.3.26",
    "2.16.840.1.101.3.4.3.10",
    "2.16.840.1.101.3.4.3.27",
    "2.16.840.1.101.3.4.3.14",
    "1.2.840.113549.1.1.10",
    "2.16.840.1.101.3.4.3.24",
    "1.2.156.10197.1.504",
    "2.16.840.1.101.3.4.3.12",
    "2.16.840.1.101.3.4.3.16",
    "2.16.840.1.101.3.4.3.11",
    "1.2.840.10045.4.1",
    "1.2.840.10046.2.1",
    "2.16.840.1.101.3.4.3.8",
    "1.2.840.10045.4.3.3",
    "2.16.840.1.101.3.4.3.17",
    "1.3.101.112",
    "2.16.840.1.101.3.4.3.13",
    "2.16.840.1.101.3.4.3.6",
    "1.3.101.111",
    "2.16.840.1.101.3.4.3.31",
    "1.2.840.113549.1.1.12",
    "2.16.840.1.101.3.4.3.7",
    "2.16.840.1.101.3.4.3.21"
]

* Added new method for getting signature algorithms
* Added method for getting union of public key
  algorithms and signature algorithms
* The regular expressions are used for getting IODs
  from openssl output

Signed-off-by: Jiri Hnidek <[email protected]>
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.

2 participants