Skip to content

Commit

Permalink
Introduce PK_Signer/PK_Verifier ::set_associated_data()
Browse files Browse the repository at this point in the history
This is a new concept introduced by FIPS 204 and 205 (ML-DSA, SLH-DSA)
where applications get the chance to provide some context that is
incorporated into their signatures. It is conceptually similar to the
associated data in an AEAD, therefore it behaves similarly in the
Signer/Verifier.

Note that algorithms that don't support AD, are supposed to always throw
when an application calls set_associated_data() on them. There is also a
predicate function is_valid_associated_data_length() for applications to
generically check for the support of it.

Co-Authored-By: Fabian Albert <[email protected]>
  • Loading branch information
reneme and FAlbertDev committed Aug 16, 2024
1 parent 6cef38c commit a3d56a4
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/lib/pubkey/pk_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
return z;
}

void PK_Ops::Signature::set_associated_data(std::span<const uint8_t> associated_data) {
BOTAN_UNUSED(associated_data);
throw Not_Implemented("This signature scheme does not support labels for signing");
}

void PK_Ops::Verification::set_associated_data(std::span<const uint8_t> associated_data) {
BOTAN_UNUSED(associated_data);
throw Not_Implemented("This signature scheme does not support labels for verification");
}

namespace {

std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
Expand Down
42 changes: 42 additions & 0 deletions src/lib/pubkey/pk_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ class BOTAN_UNSTABLE_API Decryption {
*/
class BOTAN_UNSTABLE_API Verification {
public:
/**
* Incorporate an application-defined associated data into the signature
* verification. This is useful for domain separation, but is not supported
* by all signature schemes. The valid associated data's length is checked
* beforehand, using is_valid_associated_data_length().
*
* Note: The associated data is meant to be kept between individual message
* verifications. It is the implementer's responsibility to handle
* this state correctly.
*/
virtual void set_associated_data(std::span<const uint8_t> label);

/**
* Add more data to the message currently being signed
* @param input the input to be hashed/verified
Expand All @@ -96,6 +108,15 @@ class BOTAN_UNSTABLE_API Verification {
*/
virtual std::string hash_function() const = 0;

/**
* @returns true if the associated data length is valid for this signature scheme.
* Schemes that don't support associated data always return false.
*/
virtual bool is_valid_associated_data_length(size_t length) const {
BOTAN_UNUSED(length);
return false;
}

virtual ~Verification() = default;
};

Expand All @@ -104,6 +125,18 @@ class BOTAN_UNSTABLE_API Verification {
*/
class BOTAN_UNSTABLE_API Signature {
public:
/**
* Incorporate an application-defined label into the signature. This is
* useful for domain separation, but is not supported by all signature
* schemes. The valid length of the label is checked beforehand, using
* is_valid_associated_data_length().
*
* Note: The associated data is meant to be kept between individual message
* signings. It is the implementer's responsibility to handle this
* state correctly.
*/
virtual void set_associated_data(std::span<const uint8_t> associated_data);

/**
* Add more data to the message currently being signed
* @param input the input to be hashed/signed
Expand Down Expand Up @@ -133,6 +166,15 @@ class BOTAN_UNSTABLE_API Signature {
*/
virtual std::string hash_function() const = 0;

/**
* @returns true if the label length is valid for this signature scheme
* Schemes that don't support labels always return false.
*/
virtual bool is_valid_associated_data_length(size_t length) const {
BOTAN_UNUSED(length);
return false;
}

virtual ~Signature() = default;
};

Expand Down
22 changes: 22 additions & 0 deletions src/lib/pubkey/pubkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ PK_Signer::~PK_Signer() = default;
PK_Signer::PK_Signer(PK_Signer&&) noexcept = default;
PK_Signer& PK_Signer::operator=(PK_Signer&&) noexcept = default;

void PK_Signer::set_associated_data(std::span<const uint8_t> associated_data) {
if(!is_valid_associated_data_length(associated_data.size())) {
throw Invalid_Argument("PK_Signer: Associated data does not have a supported length");
}
m_op->set_associated_data(associated_data);
}

void PK_Signer::update(std::string_view in) {
this->update(cast_char_ptr_to_uint8(in.data()), in.size());
}
Expand Down Expand Up @@ -313,6 +320,10 @@ size_t PK_Signer::signature_length() const {
}
}

bool PK_Signer::is_valid_associated_data_length(size_t length) const {
return m_op->is_valid_associated_data_length(length);
}

std::vector<uint8_t> PK_Signer::signature(RandomNumberGenerator& rng) {
std::vector<uint8_t> sig = m_op->sign(rng);

Expand Down Expand Up @@ -368,6 +379,17 @@ void PK_Verifier::set_input_format(Signature_Format format) {
m_sig_format = format;
}

bool PK_Verifier::is_valid_associated_data_length(size_t length) const {
return m_op->is_valid_associated_data_length(length);
}

void PK_Verifier::set_associated_data(std::span<const uint8_t> associated_data) {
if(!is_valid_associated_data_length(associated_data.size())) {
throw Invalid_Argument("PK_Verifier: Associated data does not have a supported length");
}
m_op->set_associated_data(associated_data);
}

void PK_Verifier::update(std::string_view in) {
this->update(cast_char_ptr_to_uint8(in.data()), in.size());
}
Expand Down
44 changes: 44 additions & 0 deletions src/lib/pubkey/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ class BOTAN_PUBLIC_API(2, 0) PK_Signer final {
return sign_message(in.data(), in.size(), rng);
}

/**
* Incorporate application-defined associated data into the signature. This
* is useful for (e.g.) domain separation, but is not supported by all
* signature schemes. This must be called at most once and before any calls
* to update().
*
* Unless reset by another call to set_associated_data(), it is kept between
* signature creations.
*
* @sa is_valid_associated_data_length
* @throws Invalid_Argument if associated data is not supported, or the data's
* length is invalid
*
* @param associated_data an application-defined associated data
*/
void set_associated_data(std::span<const uint8_t> associated_data);

/**
* Add a message part (single byte).
* @param in the byte to add
Expand Down Expand Up @@ -258,6 +275,11 @@ class BOTAN_PUBLIC_API(2, 0) PK_Signer final {
*/
std::string hash_function() const;

/**
* @returns true if the associated data's length is valid for this signature scheme
*/
bool is_valid_associated_data_length(size_t length) const;

private:
std::unique_ptr<PK_Ops::Signature> m_op;
Signature_Format m_sig_format;
Expand Down Expand Up @@ -329,6 +351,23 @@ class BOTAN_PUBLIC_API(2, 0) PK_Verifier final {
return verify_message(msg.data(), msg.size(), sig.data(), sig.size());
}

/**
* Incorporate application-defined associated data into the signature. This
* is useful for (e.g.) domain separation, but is not supported by all
* signature schemes. This must be called at most once and before any calls
* to update().
*
* Unless reset by another call to set_associated_data(), it is kept between
* signature verifications.
*
* @sa is_valid_associated_data_length
* @throws Invalid_Argument if associated data is not supported, or the data's
* length is invalid
*
* @param associated_data an application-defined associated data
*/
void set_associated_data(std::span<const uint8_t> associated_data);

/**
* Add a message part (single byte) of the message corresponding to the
* signature to be verified.
Expand Down Expand Up @@ -388,6 +427,11 @@ class BOTAN_PUBLIC_API(2, 0) PK_Verifier final {
*/
std::string hash_function() const;

/**
* @returns true if the associated data's length is valid for this signature scheme
*/
bool is_valid_associated_data_length(size_t length) const;

private:
std::unique_ptr<PK_Ops::Verification> m_op;
Signature_Format m_sig_format;
Expand Down

0 comments on commit a3d56a4

Please sign in to comment.