Skip to content

Commit 2b2381d

Browse files
committed
minimum signature hash requirements for PQC sigs and Ed25519/Ed448;
also code formatting
1 parent 6d7b4f1 commit 2b2381d

File tree

5 files changed

+152
-69
lines changed

5 files changed

+152
-69
lines changed

src/lib/crypto/signatures.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ signature_validate(const pgp::pkt::Signature & sig,
171171
res.add_error(RNP_ERROR_SIG_WEAK_HASH);
172172
}
173173

174+
/* check that hash matches minimum requirements */
175+
if (!key.sig_hash_allowed(hash.alg())) {
176+
RNP_LOG("The signature's digest size is below the minimum digest size required for "
177+
"that key.");
178+
return RNP_ERROR_SIGNATURE_INVALID;
179+
}
180+
174181
/* Finalize hash */
175182
auto hval = signature_hash_finish(sig, hash, hdr);
176183
/* compare lbits */

src/lib/generate-key.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ adjust_hash_alg(rnp_keygen_crypto_params_t &crypto)
176176
}
177177
}
178178

179-
#if defined(ENABLE_PQC)
180179
static void
181180
keygen_merge_crypto_defaults(rnp_keygen_crypto_params_t &crypto)
182181
{

src/lib/key_material.cpp

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ KeyParams::create(pgp_pubkey_alg_t alg)
162162
case PGP_PKA_KYBER768_X25519:
163163
FALLTHROUGH_STATEMENT;
164164
case PGP_PKA_KYBER1024_X448:
165-
FALLTHROUGH_STATEMENT;
165+
FALLTHROUGH_STATEMENT;
166166
case PGP_PKA_KYBER768_P256:
167167
FALLTHROUGH_STATEMENT;
168168
case PGP_PKA_KYBER1024_P384:
@@ -357,6 +357,12 @@ KeyMaterial::adjust_hash(pgp_hash_alg_t hash) const
357357
return hash;
358358
}
359359

360+
bool
361+
KeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const
362+
{
363+
return true;
364+
}
365+
360366
pgp_curve_t
361367
KeyMaterial::curve() const noexcept
362368
{
@@ -1510,6 +1516,21 @@ Ed25519KeyMaterial::sign(rnp::SecurityContext & ctx,
15101516
&ctx.rng, ed25519->sig.sig, key_.priv, hash.data(), hash.size());
15111517
}
15121518

1519+
pgp_hash_alg_t
1520+
Ed25519KeyMaterial::adjust_hash(pgp_hash_alg_t hash) const
1521+
{
1522+
if (!sig_hash_allowed(hash)) {
1523+
return PGP_HASH_SHA256;
1524+
}
1525+
return hash;
1526+
}
1527+
1528+
bool
1529+
Ed25519KeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const
1530+
{
1531+
return rnp::Hash::size(hash) >= 32;
1532+
}
1533+
15131534
size_t
15141535
Ed25519KeyMaterial::bits() const noexcept
15151536
{
@@ -1741,9 +1762,9 @@ Ed448KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams &params)
17411762
}
17421763

17431764
rnp_result_t
1744-
Ed448KeyMaterial::verify(const rnp::SecurityContext & ctx,
1745-
const SigMaterial & sig,
1746-
const rnp::secure_bytes &hash) const
1765+
Ed448KeyMaterial::verify(const rnp::SecurityContext &ctx,
1766+
const SigMaterial & sig,
1767+
const rnp::secure_bytes & hash) const
17471768
{
17481769
auto ed448 = dynamic_cast<const Ed448SigMaterial *>(&sig);
17491770
if (!ed448) {
@@ -1753,8 +1774,8 @@ Ed448KeyMaterial::verify(const rnp::SecurityContext & ctx,
17531774
}
17541775

17551776
rnp_result_t
1756-
Ed448KeyMaterial::sign(rnp::SecurityContext & ctx,
1757-
SigMaterial & sig,
1777+
Ed448KeyMaterial::sign(rnp::SecurityContext & ctx,
1778+
SigMaterial & sig,
17581779
const rnp::secure_bytes &hash) const
17591780
{
17601781
auto ed448 = dynamic_cast<Ed448SigMaterial *>(&sig);
@@ -1764,6 +1785,21 @@ Ed448KeyMaterial::sign(rnp::SecurityContext & ctx,
17641785
return ed448_sign_native(&ctx.rng, ed448->sig.sig, key_.priv, hash.data(), hash.size());
17651786
}
17661787

1788+
pgp_hash_alg_t
1789+
Ed448KeyMaterial::adjust_hash(pgp_hash_alg_t hash) const
1790+
{
1791+
if (!sig_hash_allowed(hash)) {
1792+
return PGP_HASH_SHA256;
1793+
}
1794+
return hash;
1795+
}
1796+
1797+
bool
1798+
Ed448KeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const
1799+
{
1800+
return rnp::Hash::size(hash) >= 64;
1801+
}
1802+
17671803
size_t
17681804
Ed448KeyMaterial::bits() const noexcept
17691805
{
@@ -1865,8 +1901,8 @@ X448KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams &params)
18651901
}
18661902

18671903
rnp_result_t
1868-
X448KeyMaterial::encrypt(rnp::SecurityContext & ctx,
1869-
EncMaterial &out,
1904+
X448KeyMaterial::encrypt(rnp::SecurityContext & ctx,
1905+
EncMaterial & out,
18701906
const rnp::secure_bytes &data) const
18711907
{
18721908
auto x448 = dynamic_cast<X448EncMaterial *>(&out);
@@ -1877,9 +1913,9 @@ X448KeyMaterial::encrypt(rnp::SecurityContext & ctx,
18771913
}
18781914

18791915
rnp_result_t
1880-
X448KeyMaterial::decrypt(rnp::SecurityContext & ctx,
1916+
X448KeyMaterial::decrypt(rnp::SecurityContext &ctx,
18811917
rnp::secure_bytes & out,
1882-
const EncMaterial &in) const
1918+
const EncMaterial & in) const
18831919
{
18841920
auto x448 = dynamic_cast<const X448EncMaterial *>(&in);
18851921
if (!x448) {
@@ -2139,6 +2175,21 @@ DilithiumEccKeyMaterial::sign(rnp::SecurityContext & ctx,
21392175
&ctx.rng, &dilithium->sig, dilithium->halg, hash.data(), hash.size());
21402176
}
21412177

2178+
pgp_hash_alg_t
2179+
DilithiumEccKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const
2180+
{
2181+
if (!sig_hash_allowed(hash)) {
2182+
return PGP_HASH_SHA256;
2183+
}
2184+
return hash;
2185+
}
2186+
2187+
bool
2188+
DilithiumEccKeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const
2189+
{
2190+
return rnp::Hash::size(hash) >= 32;
2191+
}
2192+
21422193
size_t
21432194
DilithiumEccKeyMaterial::bits() const noexcept
21442195
{
@@ -2259,6 +2310,21 @@ SlhdsaKeyMaterial::sign(rnp::SecurityContext & ctx,
22592310
return key_.priv.sign(&ctx.rng, &slhdsa->sig, hash.data(), hash.size());
22602311
}
22612312

2313+
pgp_hash_alg_t
2314+
SlhdsaKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const
2315+
{
2316+
if (!sig_hash_allowed(hash)) {
2317+
return PGP_HASH_SHA256;
2318+
}
2319+
return hash;
2320+
}
2321+
2322+
bool
2323+
SlhdsaKeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const
2324+
{
2325+
return rnp::Hash::size(hash) >= 32;
2326+
}
2327+
22622328
size_t
22632329
SlhdsaKeyMaterial::bits() const noexcept
22642330
{

src/lib/key_material.hpp

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class KeyMaterial {
209209

210210
/* Pick up hash algorithm, used for signing, to be compatible with key material. */
211211
virtual pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const;
212+
virtual bool sig_hash_allowed(pgp_hash_alg_t hash) const;
212213
virtual size_t bits() const noexcept = 0;
213214
virtual pgp_curve_t curve() const noexcept;
214215
KeyGrip grip() const;
@@ -465,20 +466,22 @@ class Ed25519KeyMaterial : public KeyMaterial {
465466
Ed25519KeyMaterial() : KeyMaterial(PGP_PKA_ED25519), key_{} {};
466467
std::unique_ptr<KeyMaterial> clone() override;
467468

468-
void clear_secret() noexcept override;
469-
bool parse(pgp_packet_body_t &pkt) noexcept override;
470-
bool parse_secret(pgp_packet_body_t &pkt) noexcept override;
471-
void write(pgp_packet_body_t &pkt) const override;
472-
void write_secret(pgp_packet_body_t &pkt) const override;
473-
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
474-
rnp_result_t verify(const rnp::SecurityContext &ctx,
475-
const SigMaterial & sig,
476-
const rnp::secure_bytes & hash) const override;
477-
rnp_result_t sign(rnp::SecurityContext & ctx,
478-
SigMaterial & sig,
479-
const rnp::secure_bytes &hash) const override;
480-
size_t bits() const noexcept override;
481-
pgp_curve_t curve() const noexcept override;
469+
void clear_secret() noexcept override;
470+
bool parse(pgp_packet_body_t &pkt) noexcept override;
471+
bool parse_secret(pgp_packet_body_t &pkt) noexcept override;
472+
void write(pgp_packet_body_t &pkt) const override;
473+
void write_secret(pgp_packet_body_t &pkt) const override;
474+
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
475+
rnp_result_t verify(const rnp::SecurityContext & ctx,
476+
const pgp_signature_material_t & sig,
477+
const rnp::secure_vector<uint8_t> &hash) const override;
478+
rnp_result_t sign(rnp::SecurityContext & ctx,
479+
pgp_signature_material_t & sig,
480+
const rnp::secure_vector<uint8_t> &hash) const override;
481+
pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override;
482+
bool sig_hash_allowed(pgp_hash_alg_t hash) const override;
483+
size_t bits() const noexcept override;
484+
pgp_curve_t curve() const noexcept override;
482485

483486
const std::vector<uint8_t> &pub() const noexcept;
484487
const std::vector<uint8_t> &priv() const noexcept;
@@ -525,20 +528,23 @@ class Ed448KeyMaterial : public KeyMaterial {
525528
Ed448KeyMaterial() : KeyMaterial(PGP_PKA_ED448), key_{} {};
526529
std::unique_ptr<KeyMaterial> clone() override;
527530

528-
void clear_secret() noexcept override;
529-
bool parse(pgp_packet_body_t &pkt) noexcept override;
530-
bool parse_secret(pgp_packet_body_t &pkt) noexcept override;
531-
void write(pgp_packet_body_t &pkt) const override;
532-
void write_secret(pgp_packet_body_t &pkt) const override;
533-
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
534-
rnp_result_t verify(const rnp::SecurityContext & ctx,
535-
const SigMaterial & sig,
531+
void clear_secret() noexcept override;
532+
bool parse(pgp_packet_body_t &pkt) noexcept override;
533+
bool parse_secret(pgp_packet_body_t &pkt) noexcept override;
534+
void write(pgp_packet_body_t &pkt) const override;
535+
void write_secret(pgp_packet_body_t &pkt) const override;
536+
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
537+
rnp_result_t verify(const rnp::SecurityContext & ctx,
538+
const pgp_signature_material_t & sig,
539+
const rnp::secure_vector<uint8_t> &hash) const override;
540+
rnp_result_t sign(rnp::SecurityContext & ctx,
541+
pgp_signature_material_t & sig,
536542
const rnp::secure_vector<uint8_t> &hash) const override;
537-
rnp_result_t sign(rnp::SecurityContext & ctx,
538-
SigMaterial & sig,
539-
const rnp::secure_vector<uint8_t> &hash) const override;
540-
size_t bits() const noexcept override;
541-
pgp_curve_t curve() const noexcept override;
543+
pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override;
544+
bool sig_hash_allowed(pgp_hash_alg_t hash) const override;
545+
546+
size_t bits() const noexcept override;
547+
pgp_curve_t curve() const noexcept override;
542548

543549
const std::vector<uint8_t> &pub() const noexcept;
544550
const std::vector<uint8_t> &priv() const noexcept;
@@ -624,12 +630,14 @@ class DilithiumEccKeyMaterial : public KeyMaterial {
624630
void write(pgp_packet_body_t &pkt) const override;
625631
void write_secret(pgp_packet_body_t &pkt) const override;
626632
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
627-
rnp_result_t verify(const rnp::SecurityContext &ctx,
628-
const SigMaterial & sig,
629-
const rnp::secure_bytes & hash) const override;
630-
rnp_result_t sign(rnp::SecurityContext & ctx,
631-
SigMaterial & sig,
632-
const rnp::secure_bytes &hash) const override;
633+
rnp_result_t verify(const rnp::SecurityContext & ctx,
634+
const pgp_signature_material_t & sig,
635+
const rnp::secure_vector<uint8_t> &hash) const override;
636+
rnp_result_t sign(rnp::SecurityContext & ctx,
637+
pgp_signature_material_t & sig,
638+
const rnp::secure_vector<uint8_t> &hash) const override;
639+
pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override;
640+
bool sig_hash_allowed(pgp_hash_alg_t hash) const override;
633641
size_t bits() const noexcept override;
634642

635643
const pgp_dilithium_exdsa_composite_public_key_t & pub() const noexcept;
@@ -653,12 +661,14 @@ class SlhdsaKeyMaterial : public KeyMaterial {
653661
void write(pgp_packet_body_t &pkt) const override;
654662
void write_secret(pgp_packet_body_t &pkt) const override;
655663
bool generate(rnp::SecurityContext &ctx, const KeyParams &params) override;
656-
rnp_result_t verify(const rnp::SecurityContext &ctx,
657-
const SigMaterial & sig,
658-
const rnp::secure_bytes & hash) const override;
659-
rnp_result_t sign(rnp::SecurityContext & ctx,
660-
SigMaterial & sig,
661-
const rnp::secure_bytes &hash) const override;
664+
rnp_result_t verify(const rnp::SecurityContext & ctx,
665+
const pgp_signature_material_t & sig,
666+
const rnp::secure_vector<uint8_t> &hash) const override;
667+
rnp_result_t sign(rnp::SecurityContext & ctx,
668+
pgp_signature_material_t & sig,
669+
const rnp::secure_vector<uint8_t> &hash) const override;
670+
pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override;
671+
bool sig_hash_allowed(pgp_hash_alg_t hash) const override;
662672
size_t bits() const noexcept override;
663673

664674
const pgp_sphincsplus_public_key_t & pub() const noexcept;

src/tests/ffi-key-sig.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2627,7 +2627,7 @@ TEST_F(rnp_tests, test_ffi_key_self_certification_features)
26272627
#if defined(ENABLE_PQC)
26282628
TEST_F(rnp_tests, test_ffi_verify_detached_pqc_test_vector)
26292629
{
2630-
std::string msg = "Testing\n";
2630+
std::string msg = "Testing\n";
26312631
std::vector<std::pair<std::string, std::string>> key_sig_pairs = {
26322632
{"data/draft-ietf-openpgp-pqc/v6-mldsa-65-sample-pk.asc",
26332633
"data/draft-ietf-openpgp-pqc/v6-mldsa-65-sample-signature.asc"},
@@ -2641,24 +2641,25 @@ TEST_F(rnp_tests, test_ffi_verify_detached_pqc_test_vector)
26412641
"data/draft-ietf-openpgp-pqc/v6-slhdsa-256s-sample-signature.asc"}};
26422642

26432643
for (auto key_sig_pair : key_sig_pairs) {
2644-
rnp_ffi_t ffi = NULL;
2645-
rnp_input_t input = NULL;
2646-
rnp_input_t signature = NULL;
2647-
rnp_op_verify_t verify = NULL;
2648-
2649-
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
2650-
assert_true(import_all_keys(ffi, key_sig_pair.first));
2651-
assert_rnp_success(rnp_input_from_memory(&input, (uint8_t*)msg.c_str(), msg.length(), false));
2652-
assert_non_null(input);
2653-
assert_rnp_success(rnp_input_from_path(&signature, key_sig_pair.second.c_str()));
2654-
assert_non_null(signature);
2655-
2656-
assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
2657-
assert_rnp_success(rnp_op_verify_execute(verify));
2658-
assert_rnp_success(rnp_op_verify_destroy(verify));
2659-
assert_rnp_success(rnp_input_destroy(input));
2660-
assert_rnp_success(rnp_input_destroy(signature));
2661-
assert_rnp_success(rnp_ffi_destroy(ffi));
2644+
rnp_ffi_t ffi = NULL;
2645+
rnp_input_t input = NULL;
2646+
rnp_input_t signature = NULL;
2647+
rnp_op_verify_t verify = NULL;
2648+
2649+
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
2650+
assert_true(import_all_keys(ffi, key_sig_pair.first));
2651+
assert_rnp_success(
2652+
rnp_input_from_memory(&input, (uint8_t *) msg.c_str(), msg.length(), false));
2653+
assert_non_null(input);
2654+
assert_rnp_success(rnp_input_from_path(&signature, key_sig_pair.second.c_str()));
2655+
assert_non_null(signature);
2656+
2657+
assert_rnp_success(rnp_op_verify_detached_create(&verify, ffi, input, signature));
2658+
assert_rnp_success(rnp_op_verify_execute(verify));
2659+
assert_rnp_success(rnp_op_verify_destroy(verify));
2660+
assert_rnp_success(rnp_input_destroy(input));
2661+
assert_rnp_success(rnp_input_destroy(signature));
2662+
assert_rnp_success(rnp_ffi_destroy(ffi));
26622663
}
26632664
}
26642665
#endif

0 commit comments

Comments
 (0)