| From: | Filip Janus <fjanus(at)redhat(dot)com> |
|---|---|
| To: | Michael Paquier <michael(at)paquier(dot)xyz> |
| Cc: | Pgsql Hackers <pgsql-hackers(at)postgresql(dot)org> |
| Subject: | Re: Channel binding for post-quantum cryptography |
| Date: | 2025-10-26 10:20:53 |
| Message-ID: | CAFjYY+L4egDkaKYkfNdfw8w1=fpNJq1Q5-AJbPDXxFeuUVihbA@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
Thank you for the detailed feedback. Let me address your points:
Test Case
=========
I have prepared a test case following the pattern from commit 9244c11afe23
(RSA-PSS fix).
Regarding the Hash Algorithm
=============================
You are correct that, according to RFC 5929, we should ideally use the hash
function associated with the certificate's signatureAlgorithm. However, if
I understand it correctly, there are distinctions with ML-DSA:
I investigated OpenSSL's API to retrieve the hash algorithm used by ML-DSA,
and I haven't found a suitable solution.
ML-DSA seems to have an internal structure but no public API to extract
SHAKE128/256 configuration
The ML-DSA Specifies
ML-DSA (FIPS 204) uses SHAKE internally:
- ML-DSA-44: SHAKE128 (128-bit security)
- ML-DSA-65: SHAKE256 (192-bit security)
- ML-DSA-87: SHAKE256 (256-bit security)
However, this is a different approach from traditional signature algorithms:
- Traditional (e.g., RSA-SHA256): Hash is a separate, associated algorithm
that can be queried
- ML-DSA: SHAKE is an internal component of the signature algorithm, not an
associated digest for external use
ML-DSA doesn't have an "associated" hash function in the sense that
RSA-SHA256 does. The SHAKE function is internal to the signing process, not
a separate digest step. For the purpose of channel binding (hashing the
entire certificate), we need a traditional hash function. So that's why
I've chosen SHA-256
SHA-256 is appropriate because:
1. It matches the security level of ML-DSA-65 (both ~256-bit security)
2. RFC 5929 recommends SHA-256 for unknown/unsupported algorithms
3. It's the standard fallback used throughout the codebase
4. SHAKE256 (via EVP_shake256()) is an XOF (eXtendable Output Function),
not a traditional fixed-size hash suitable for this use case
Regarding NIDs and Future Extensions, I would expect growth, but I am not a
security specialist.
Current Patch Status
====================
I'm keeping the current patch as-is for now, and I am adding the requested
test case in a separate commit.
-Filip-
po 20. 10. 2025 v 10:06 odesílatel Michael Paquier <michael(at)paquier(dot)xyz>
napsal:
> On Mon, Oct 20, 2025 at 09:12:52AM +0200, Filip Janus wrote:
> > The problem is caused by a difference between the currently used
> algorithms
> > and post-quantum ones. For example, commonly used algorithms like RSA
> have
> > a defined digest algorithm, but ML-DSA does not.
> >
> > PostgreSQL's channel binding implementation expects all signature
> > algorithms to have a traditional digest mapping, but post-quantum
> > algorithms such as ML-DSA use their hash function internally as part of
> the
> > signature process.
>
> Noted.
>
> > As a result, the connection fails with the following error:
> >
> > could not find digest for NID UNDEF
> >
> > The issue can be worked around by disabling channel binding.
> >
> > Although the RFC is not entirely clear on how to handle this situation,
> in
> > my patch I propose using SHA-256 as the default digest in such cases.
>
> Based on the RFC at [1], we have indeed:
> if the certificate's signatureAlgorithm uses a single hash function
> and that hash function neither MD5 nor SHA-1, then use the hash
> function associated with the certificate's signatureAlgorithm;
>
> So it would be essential to reuse the hash function used by this
> algorithm. Except that you are saying that we have no way to retrieve
> that, even if it's a different routine than EVP_get_digestbynid()?
> Enforcing blindly SHA-256 does not seem to be the right move because
> it could enforce an incorrect behavior, even if it would be more
> user-friendly in some cases like this one.
>
> So, X509_get_signature_info() is able to return an algo NID that we
> can then use to decide which algo type we should take. I can see
> three NIDs associated to ML-DSA: NID_ML_DSA_44, NID_ML_DSA_65 and
> NID_ML_DSA_87. Could this list grow?
>
> Based on ml-dsa.md, I am wondering if we could do something based on
> ML_DSA_PARAM. I am not sure, but OpenSSL, while being a spaghetti
> code base, usually has some internal way to extract some of its
> contents. Saying that, they tend to hide more internals behind
> pointers, 3.0 has added some of that stuff.
>
> A good first step would be to design a reproducible test case to
> investigate the issue. Could it be possible to craft a test case that
> could then be added into the tree? We have automated tests in
> src/test/ssl/. See for example the level of craft done for a similar
> past issue, as of commit 9244c11afe23. That would be the minimum
> required for a potential fix.
>
> Note that the use of X509_get_signature_info() is conditional in our
> code, so your patch would likely fail to compile depending on the
> version of OpenSSL linked to. The minimum version of OpenSSL
> supported by PG on HEAD is 1.1.1. On the oldest stable branches (v13
> or v14), this requirement is.. Cough.. 1.0.1.
>
> [1]: https://datatracker.ietf.org/doc/html/rfc5929#section-4.1
> --
> Michael
>
| Attachment | Content-Type | Size |
|---|---|---|
| 0002-Support-post-quantum-signature-algorithms-in-SCRAM-c.patch | application/octet-stream | 4.7 KB |
| 0001-Add-regression-test-for-ML-DSA-channel-binding-suppo.patch | application/octet-stream | 4.3 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Dmitry Dolgov | 2025-10-26 11:16:14 | Re: Bug in pg_stat_statements |
| Previous Message | Joel Jacobson | 2025-10-26 07:08:42 | Re: Optimize LISTEN/NOTIFY |