Skip to content

Commit

Permalink
FFI: Add functions rnp_key_signature_create/rnp_signature_set_revoker…
Browse files Browse the repository at this point in the history
…/rnp_key_signature_sign.
  • Loading branch information
ni4 committed Dec 27, 2023
1 parent ac3723d commit d3b1099
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 0 deletions.
44 changes: 44 additions & 0 deletions include/rnp/rnp.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ typedef uint32_t rnp_result_t;
#define RNP_VERIFY_REQUIRE_ALL_SIGS (1U << 1)
#define RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT (1U << 2)

/**
* Revocation key flags.
*/
#define RNP_REVOKER_SENSITIVE (1U << 0)

/**
* Return a constant string describing the result code
*/
Expand Down Expand Up @@ -1519,6 +1524,45 @@ RNP_API rnp_result_t rnp_key_get_signature_at(rnp_key_handle_t key,
size_t idx,
rnp_signature_handle_t *sig);

/**
* @brief Create new blank signature, issued by signer. It may be customized via the
* rnp_signature_set_* calls, and finalized via the rnp_signature_sign() call.
*
* @param signer signing key, must be secret, and must exist in the keyring up to the
* rnp_signature_sign() call. Cannot be NULL.
* @param sigtype type of the signature. See rnp_signature_get_type() for possible values.
* @param sig on success signature handle will be stored here. It is initialized with current
* creation time, default hash algorithm and version.
* @return RNP_SUCCESS or error code if failued.
*/
RNP_API rnp_result_t rnp_key_signature_create(rnp_key_handle_t signer,
const char * sigtype,
rnp_signature_handle_t *sig);

/**
* @brief Add designated revoker subpacket to the signature. See RFC 4880, section 5.2.3.15.
* Only single revoker could be set - subsequent calls would overwrite the previous one.
*
* @param sig editable key signature handle, i.e. created with rnp_key_signature_create().
* @param revoker revoker's key.
* @param flags additional flags. The following flag is currently supported:
* RNP_REVOKER_SENSITIVE: information about the revocation key should be
* considered as sensitive. See RFC for the details.
* @return RNP_SUCCESS or error code if failued.
*/
RNP_API rnp_result_t rnp_key_signature_set_revoker(rnp_signature_handle_t sig,
rnp_key_handle_t revoker,
uint32_t flags);

/**
* @brief Finalize populating and sign signature, created with rnp_key_signature_create, and
* add it to the corresponding key.
*
* @param sig signature handle.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_key_signature_sign(rnp_signature_handle_t sig);

/**
* @brief Get number of the designated revokers for the key. Designated revoker is a key, which
* is allowed to revoke this key.
Expand Down
1 change: 1 addition & 0 deletions src/lib/ffi-priv-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct rnp_signature_handle_st {
const pgp_key_t *key;
pgp_subsig_t * sig;
bool own_sig;
bool new_sig;
};

struct rnp_recipient_handle_st {
Expand Down
129 changes: 129 additions & 0 deletions src/lib/rnp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6174,6 +6174,135 @@ try {
}
FFI_GUARD

static bool
is_key_signature_supported(int stype)
{
/* We support creation of only direct-key signature for now */
return stype == PGP_SIG_DIRECT;
}

rnp_result_t
rnp_key_signature_create(rnp_key_handle_t signer,
const char * sigtype,
rnp_signature_handle_t *sig)
try {
if (!signer || !sigtype || !sig) {
return RNP_ERROR_NULL_POINTER;
}
auto stype = id_str_pair::lookup(sig_type_map, sigtype);
if (!is_key_signature_supported(stype)) {
FFI_LOG(signer->ffi, "Not yet supported sigtype: %s", sigtype);
return RNP_ERROR_BAD_PARAMETERS;
}

pgp_key_t *sigkey = get_key_require_secret(signer);
if (!sigkey) {
return RNP_ERROR_BAD_PARAMETERS;
}
*sig = (rnp_signature_handle_t) calloc(1, sizeof(**sig));
if (!*sig) {
return RNP_ERROR_OUT_OF_MEMORY;
}
try {
pgp_signature_t sigpkt;
sigkey->sign_init(signer->ffi->rng(),
sigpkt,
DEFAULT_PGP_HASH_ALG,
signer->ffi->context.time(),
sigkey->version());
sigpkt.set_type(static_cast<pgp_sig_type_t>(stype));
(*sig)->sig = new pgp_subsig_t(sigpkt);
(*sig)->ffi = signer->ffi;
(*sig)->key = sigkey;
(*sig)->own_sig = true;
(*sig)->new_sig = true;
} catch (const std::exception &e) {
FFI_LOG(signer->ffi, "%s", e.what());
free(*sig);
*sig = NULL;
return RNP_ERROR_OUT_OF_MEMORY;
}

return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_key_signature_set_revoker(rnp_signature_handle_t sig,
rnp_key_handle_t revoker,
uint32_t flags)
try {
if (!sig || !revoker) {
return RNP_ERROR_NULL_POINTER;
}
if (!sig->new_sig) {
return RNP_ERROR_BAD_PARAMETERS;
}
bool sensitive = extract_flag(flags, RNP_REVOKER_SENSITIVE);
if (flags) {
FFI_LOG(sig->ffi, "Unsupported flags: %" PRIu32, flags);
return RNP_ERROR_BAD_PARAMETERS;
}
auto key = get_key_prefer_public(revoker);
if (!key) {
return RNP_ERROR_BAD_PARAMETERS;
}
sig->sig->sig.set_revoker(*key, sensitive);
return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_key_signature_sign(rnp_signature_handle_t sig)
try {
if (!sig) {
return RNP_ERROR_NULL_POINTER;
}
if (!sig->new_sig) {
return RNP_ERROR_BAD_PARAMETERS;
}
auto &sigpkt = sig->sig->sig;
if (!is_key_signature_supported(sigpkt.type())) {
return RNP_ERROR_BAD_STATE;
}
/* Locate signer */
auto signer = sig->ffi->secring->get_signer(sigpkt);
if (!signer) {
return RNP_ERROR_BAD_STATE;
}
/* Unlock if needed */
rnp::KeyLocker seclock(*signer);
if (signer->is_locked() && !signer->unlock(sig->ffi->pass_provider)) {
FFI_LOG(sig->ffi, "Failed to unlock secret key");
return RNP_ERROR_BAD_PASSWORD;
}
/* Sign */
switch (sigpkt.type()) {
case PGP_SIG_DIRECT:
signer->sign_direct(signer->pkt(), sigpkt, sig->ffi->context);
break;
default:
FFI_LOG(sig->ffi, "Not yet supported signature type.");
return RNP_ERROR_BAD_STATE;
}
/* Add to the keyring(s) */
auto &addsig = signer->add_sig(sigpkt, PGP_UID_NONE, true);
signer->refresh_data(sig->ffi->context);
auto sigpub = sig->ffi->pubring->get_signer(sigpkt);
if (sigpub) {
sigpub->add_sig(sigpkt, PGP_UID_NONE, true);
sigpub->refresh_data(sig->ffi->context);
}
/* Replace owned sig with pointer to the key's one */
delete sig->sig;
sig->sig = &addsig;
sig->own_sig = false;
sig->new_sig = false;

return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_key_get_revoker_count(rnp_key_handle_t handle, size_t *count)
try {
Expand Down

0 comments on commit d3b1099

Please sign in to comment.