Skip to content

Conversation

randombit
Copy link
Owner

@randombit randombit commented Feb 22, 2023

Fixes #2841 and #3313

@reneme review is optional but I figure you would be interested. It is probably easier to review commit-by-commit. Also important note: Dilithium X.509 is still broken. The old tests used Botan::get_sig_paddings to get the padding parameters, but this returned an empty list for Dilithium. If I enable the tests for Dilithium, things fail.

#3319 captures some followup items.

@randombit randombit requested a review from reneme February 22, 2023 08:57
Previously if RFC 6979 was enabled, we would test only that file.
And if it was disabled, we would test only the CAVS file.

Now test signature *generation* using whichever method is enabled,
but also test verification of the signatures from the other method.
Remove support for message prefixes from the PK_Ops base classes,
since it was only used for ECKCDSA.
Only RSA still supports this now that Rabin-Williams and NR have been
removed; it's easier to move that logic to the RSA specific impl.
The behavior of EMSA1 and BigInt::from_bytes_with_max_bits were fighting
with each other, which led to weird corner cases.

Note the change to ecdsa_rfc6979.vec is a reversion of the change made
in ffaa805

Fixes GH #2841 and GH #3313
This effectively sidelines the EMSA1/EMSA_Raw code for (EC)DSA, GOST,
and company.
At least keeping parity with what is done on master currently.
@randombit randombit force-pushed the jack/emsa-improvements branch from 5a42882 to 9eb96f3 Compare February 22, 2023 13:36
@codecov-commenter
Copy link

codecov-commenter commented Feb 22, 2023

Codecov Report

Base: 87.99% // Head: 88.02% // Increases project coverage by +0.03% 🎉

Coverage data is based on head (2c23729) compared to base (892988d).
Patch coverage: 76.70% of modified lines in pull request are covered.

❗ Current head 2c23729 differs from pull request most recent head d99eef1. Consider uploading reports for the commit d99eef1 to get more accurate results

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3315      +/-   ##
==========================================
+ Coverage   87.99%   88.02%   +0.03%     
==========================================
  Files         608      608              
  Lines       68680    68758      +78     
  Branches     6845     6850       +5     
==========================================
+ Hits        60436    60526      +90     
+ Misses       5395     5368      -27     
- Partials     2849     2864      +15     
Impacted Files Coverage Δ
src/lib/asn1/oid_maps.cpp 100.00% <ø> (ø)
src/lib/pk_pad/emsa.cpp 65.15% <ø> (-6.68%) ⬇️
src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp 79.36% <0.00%> (+1.94%) ⬆️
src/lib/pk_pad/emsa_pssr/pssr.cpp 90.16% <0.00%> (+8.56%) ⬆️
src/lib/pk_pad/iso9796/iso9796.cpp 96.00% <ø> (+2.97%) ⬆️
src/lib/pubkey/gost_3410/gost_3410.cpp 79.27% <0.00%> (-0.55%) ⬇️
src/lib/x509/x509_dn_ub.cpp 100.00% <ø> (ø)
src/lib/prov/pkcs11/p11_mechanism.cpp 74.32% <30.00%> (-2.39%) ⬇️
src/lib/pubkey/ecgdsa/ecgdsa.cpp 81.63% <33.33%> (-1.06%) ⬇️
src/lib/pubkey/dsa/dsa.cpp 82.14% <37.50%> (-1.39%) ⬇️
... and 35 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Copy link
Collaborator

@reneme reneme left a comment

Choose a reason for hiding this comment

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

I skimmed over the changes and didn't find any obvious blunder. But frankly I'm lacking a good enough overview of the EMSA implementations to give a decent review.

Anything we can do to help with Dilithium, though?

Comment on lines 245 to 278
switch(m_code)
{
case RSA_PKCS1_SHA1:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA3(SHA-1)"), AlgorithmIdentifier::USE_NULL_PARAM);
case RSA_PKCS1_SHA256:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA3(SHA-256)"), AlgorithmIdentifier::USE_NULL_PARAM);
case RSA_PKCS1_SHA384:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA3(SHA-384)"), AlgorithmIdentifier::USE_NULL_PARAM);
case RSA_PKCS1_SHA512:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA3(SHA-512)"), AlgorithmIdentifier::USE_NULL_PARAM);

case ECDSA_SHA1:
return AlgorithmIdentifier(OID::from_string("ECDSA/EMSA1(SHA-1)"), AlgorithmIdentifier::USE_EMPTY_PARAM);
case ECDSA_SHA256:
return AlgorithmIdentifier(OID::from_string("ECDSA/EMSA1(SHA-256)"), AlgorithmIdentifier::USE_EMPTY_PARAM);
case ECDSA_SHA384:
return AlgorithmIdentifier(OID::from_string("ECDSA/EMSA1(SHA-384)"), AlgorithmIdentifier::USE_EMPTY_PARAM);
case ECDSA_SHA512:
return AlgorithmIdentifier(OID::from_string("ECDSA/EMSA1(SHA-512)"), AlgorithmIdentifier::USE_EMPTY_PARAM);

case RSA_PSS_SHA256:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA4"),
hex_decode("3039A00F300D06096086480165030402010500A11C301A06092A864886F70D010108300D06096086480165030402010500A203020120A303020101"));
case RSA_PSS_SHA384:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA4"),
hex_decode("3039A00F300D06096086480165030402020500A11C301A06092A864886F70D010108300D06096086480165030402020500A203020130A303020101"));
case RSA_PSS_SHA512:
return AlgorithmIdentifier(OID::from_string("RSA/EMSA4"),
hex_decode("3039A00F300D06096086480165030402030500A11C301A06092A864886F70D010108300D06096086480165030402030500A203020140A303020101"));

default:
// Note that Ed25519 and Ed448 end up here
return AlgorithmIdentifier();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as last year: Sad that we need to scatter those mappings around the code. But then again: it feels like every protocol has their own particularities that make it hard to abstract this.

Anyway: Maybe at least add a comment to the hex_decode-ed EMSA4 parameters explaining what's inside the magic strings?
In the linked comment, I regenerated those for every invocation. Less efficient but easier to understand:

   auto pss_params = [](const std::string hash_name)
      {
         const AlgorithmIdentifier hash_id(hash_name, AlgorithmIdentifier::USE_NULL_PARAM);
         const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode());

         std::vector<uint8_t> parameters;
         DER_Encoder(parameters)
            .start_sequence()
            .start_context_specific(0).encode(hash_id).end_cons()
            .start_context_specific(1).encode(mgf_id).end_cons()
            .start_context_specific(2).encode(HashFunction::create(hash_name)->output_length()).end_cons()
            .start_context_specific(3).encode(size_t(1)).end_cons() // trailer field
            .end_cons();

         return parameters;
      };

Still wondering whether DER_Encoder could do this as a constexpr generation. Purely academic question though.

Copy link
Owner Author

Choose a reason for hiding this comment

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

In this instance though, the specific values we're encoding don't even matter. That is, TLS 1.3 could have just as easily mandated that the parameters be empty, or be the raw binary ASCII "I_PINKY_SWEAR_THIS_IS_PSS". In the context of TLS 1.3, no additional information is conveyed; there is a 1:1 mapping between the signature_algorithm enumeration, and the DER-encoded PssParams.

This could probably be cleaned up a bit by adding an explicit type for PssParams.

@randombit
Copy link
Owner Author

@reneme A lot of code in this area is more complicated than it needed to be, as a result of some historical blunders

  • For signature padding in general, and its interactions with signatures schemes, following the approach of IEEE 1363, which turned out to be kind of a dead end as standards go.
  • Trying to be overly general, leading to us supporting combinations that are definitely not a good idea (like supporting RSA with unpadded hashes - that's been deprecated for some time and I'm hoping to kill it for good for 3.0)
  • Supporting multiple signatures schemes with message recovery (namely Rabin-Williams and Nyberg-Rueppel, along with RSA), which made certain generalizations seem more beneficial.

This PR (and followup work in #3319) will hopefully address a lot of these

@randombit randombit merged commit 2e51792 into master Feb 23, 2023
if(m_output_length > 0 && m_bits.size() != m_output_length)
{
m_bits.resize(0);
throw Invalid_Argument("EMSA_Raw was configured to use a " +
Copy link
Collaborator

@lieser lieser Feb 24, 2023

Choose a reason for hiding this comment

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

I guess this is a copy and paste error and EMSA_Raw should probably be RawHashFunction.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Ah thank you, yes

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.

ECDSA producing unverifiable or incorrect signatures for some curves
4 participants