Skip to content

Conversation

@jahkosha
Copy link
Contributor

This fixes #3713 and #10226.

Instead of using the script written by @misterzed88 in #10226 to generate modified tests vectors, I did directly implement the same logic in the test infrastructure, so we can reuse directly the NIST (or others...) vectors stored in the tests.

@alex
Copy link
Member

alex commented Oct 24, 2025

I haven't reviewed in depth -- but I don't think we should use None to signify this, I think we should have a dedicated sentinel, Raw<Something> perhaps. None looks like a reasonable default, but this is the opposite of that :-)

@reaperhulk wdyt?

@jahkosha
Copy link
Contributor Author

@alex yeah that is a fair concern 👍 in some early attempt I did add a NoHash hashes instead of using None, but I was afraid that would cause even more confusion so eventually I went with None.

I'll be happy to apply what you folks think is the best, if possible, please provide pointers where in the code-base a similar pattern is used so I can take inspiration from it.

@misterzed88
Copy link
Contributor

misterzed88 commented Oct 25, 2025

I haven't reviewed in depth -- but I don't think we should use None to signify this, I think we should have a dedicated sentinel, Raw<Something> perhaps. None looks like a reasonable default, but this is the opposite of that :-)

@reaperhulk wdyt?

I would like to highlight that the API already uses None for this purpose (for the RSA signature recover functionality, ref. issue #5495). So whatever you decide, you may want to use the same method in all the API functions to make them symmetric.

@reaperhulk
Copy link
Member

Hmm, the inconsistency is a bit unfortunate. I'd be inclined to do a RawNoDigestInfo (or perhaps just NoDigestInfo?) sentinel here and then also add that as an option on the signature recovery method while retaining None for backwards compatibility. So this signature would look like sign(value, PKCS1v15(), RawNoDigestInfo()) or sign(value, PKCS1v15(), NoDigestInfo()).

@jahkosha
Copy link
Contributor Author

jahkosha commented Nov 4, 2025

@alex @reaperhulk I did add a sentinel NoDigestInfo and support it also on recover_data_from_signature

Please have an other look and let me know what you think

Copy link
Member

@reaperhulk reaperhulk left a comment

Choose a reason for hiding this comment

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

We also need docs for this new value in RSAPrivateKey.sign

signature = private_key.sign(
binascii.unhexlify(
compute_rsa_hash_digest(
backend, hashes.SHA1(), example["message"]
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer we used SHA256 for the tests here because otherwise we'll increasingly have coverage challenges as more and more things disable SHA1.

Copy link
Contributor Author

@jahkosha jahkosha Nov 17, 2025

Choose a reason for hiding this comment

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

The problem with that change is that the test vectors we use here (pkcs1v15sign-vectors.txt) do use SHA1.

Copy link
Member

Choose a reason for hiding this comment

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

We don't need to use pkcs1v15sign-vectors.txt here, we can use SigVer15_186-3.rsp and filter to passing non-SHA1 tests.

@jahkosha
Copy link
Contributor Author

Hey @reaperhulk, I finally had some time to have an other pass on this.

I could apply your feedback, there is just one comment I could not fix (SHA1 vs SHA256) because SHA1 is used by the test vectors themself (#13740 (comment)).

Please have a look at the last two commits and let me know if some more polish is needed.

Many thanks!


.. class:: NoDigestInfo()

.. versionadded:: 47.0
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.. versionadded:: 47.0
.. versionadded:: 47.0.0

signature = private_key.sign(
binascii.unhexlify(
compute_rsa_hash_digest(
backend, hashes.SHA1(), example["message"]
Copy link
Member

Choose a reason for hiding this comment

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

We don't need to use pkcs1v15sign-vectors.txt here, we can use SigVer15_186-3.rsp and filter to passing non-SHA1 tests.

@reaperhulk
Copy link
Member

Oh, forgot one thing: we need a changelog entry in CHANGELOG.rst for this. Something like:

Added support for PKCS1v15 signing without DigestInfo using :class:~cryptography.path.to.NoDigestInfo.

@jahkosha
Copy link
Contributor Author

jahkosha commented Nov 18, 2025

@reaperhulk I gave a try at using SigVer15_186-3.rsp instead of pkcs1v15sign-vectors.txt, but the fields does not match between load_pkcs1_vectors and load_rsa_nist_vectors.

I could add the code to parse signature (S) and message (Msg), but I don't see in SigVer15_186-3.rsp some of the fields used to create the private key, namely: dmp1, dmq1 and iqmp.

Also I'm not sure how to differentiate private/public exponent... could you please give some guidance?

For reference, here is the field used by the test:

                private_key = rsa.RSAPrivateNumbers(
                    p=private["p"],
                    q=private["q"],
                    d=private["private_exponent"],
                    dmp1=private["dmp1"],
                    dmq1=private["dmq1"],
                    iqmp=private["iqmp"],
                    public_numbers=rsa.RSAPublicNumbers(
                        e=private["public_exponent"], n=private["modulus"]
                    ),

I looked in the rest of the codebase but I could not find any test that use SigVer15_186-3.rsp to build private keys.

@misterzed88
Copy link
Contributor

I could add the code to parse signature (S) and message (Msg), but I don't see in SigVer15_186-3.rsp some of the fields used to create the private key, namely: dmp1, dmq1 and iqmp.

In a straightforward RSA implementation it would have been sufficient with the modulus n and the private exponent d for computations with the private key (as illustrated in the test script rsavec.py). There is also a more efficient computation, called the Chinese Reminder Theorem (CRT), which requires the parameters p, q, dmp1, dmq1 and iqmp.

The cryptography library always requires the CRT parameters to be available. Since they are not present in SigVer15_186-3.rsp they must be computed from n, e and d as follows:

p, q = rsa_recover_prime_factors(n, e, d)
dmp1 = rsa_crt_dmp1(d, p)
dmq1 = rsa_crt_dmq1(d, q)
iqmp = rsa_crt_iqmp(p, q)

It would of course be nice if the lib supported private RSA with only d being available, using it directly or with optional CRT precomputation support (for better efficiency in case the key is used multiple times). But that is a diffent story.

Perhaps the maintainers have more context or a better answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Allow signing to exclude hash constant

5 participants