Skip to content

Commit

Permalink
FFI: Add API to retrieve raw subpacket data.
Browse files Browse the repository at this point in the history
  • Loading branch information
ni4 committed Oct 9, 2024
1 parent 7f0adc1 commit 27b1ab7
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 7 deletions.
79 changes: 79 additions & 0 deletions include/rnp/rnp.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ typedef struct rnp_op_encrypt_st * rnp_op_encrypt_t;
typedef struct rnp_identifier_iterator_st *rnp_identifier_iterator_t;
typedef struct rnp_uid_handle_st * rnp_uid_handle_t;
typedef struct rnp_signature_handle_st * rnp_signature_handle_t;
typedef struct rnp_sig_subpacket_st * rnp_sig_subpacket_t;
typedef struct rnp_recipient_handle_st * rnp_recipient_handle_t;
typedef struct rnp_symenc_handle_st * rnp_symenc_handle_t;

Expand Down Expand Up @@ -1893,6 +1894,84 @@ RNP_API rnp_result_t rnp_signature_get_hash_alg(rnp_signature_handle_t sig, char
*/
RNP_API rnp_result_t rnp_signature_get_creation(rnp_signature_handle_t sig, uint32_t *create);

/**
* @brief Get number of the signature subpackets.
*
* @param sig signature handle, cannot be NULL.
* @param count on success number of the subpackets will be stored here.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_count(rnp_signature_handle_t sig, size_t *count);

/**
* @brief Get signature subpacket at the specified position.
*
* @param sig signature handle, cannot be NULL.
* @param idx index of the subpacket (see rnp_signature_subpacket_count for the total amount)
* @param subpkt on success handle to the subpacket object will be stored here. Must be later
* destroyed via the rnp_signature_subpacket_destroy() call.
* @return RNP_SUCCESS on success, RNP_ERROR_NOT_FOUND if index is out of bounds, or any other
* error code if failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_at(rnp_signature_handle_t sig,
size_t idx,
rnp_sig_subpacket_t * subpkt);

/**
* @brief Find the signature subpacket matching criteria.
*
* @param sig signature handle, cannot be NULL.
* @param type type of the subpacket as per OpenPGP specification.
* @param hashed if true, then subpacket will be looked only in hashed area. If false - then in
* both, hashed and unhashed areas.
* @param skip number of matching subpackets to skip, allowing to iterate over the subpackets
* of the same type.
* @param subpkt on success handle to the subpacket will be stored here. Must be destroyed via
* the rnp_signature_subpacket_destroy() call.
* @return RNP_SUCCESS if subpacket found, or RNP_ERROR_NOT_FOUND otherwise. Any other value
* would mean that search failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_find(rnp_signature_handle_t sig,
uint8_t type,
bool hashed,
size_t skip,
rnp_sig_subpacket_t * subpkt);

/**
* @brief Get the subpacket info.
*
* @param subpkt signature subpacket handle, cannot be NULL.
* @param type type of the subpacket as per OpenPGP specification will be stored here.
* @param hashed whether subpackets is stored in hased or unhashed area.
* @param critical whether subpacket has critical bit set.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_info(rnp_sig_subpacket_t subpkt,
uint8_t * type,
bool * hashed,
bool * critical);

/**
* @brief Get signature subpacket raw data.
*
* @param subpkt signature subpacket handle, cannot be NULL.
* @param data pointer to raw data will be stored here. Must be deallocated via the
* rnp_buffer_destroy() call.
* @param size size of the data will be stored here.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_data(rnp_sig_subpacket_t subpkt,
uint8_t ** data,
size_t * size);

/**
* @brief Destroy the subpacket object.
*
* @param subpkt initialized signature subpacket handle, cannot be NULL.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_subpacket_destroy(rnp_sig_subpacket_t subpkt);

/** Get the signature expiration time as number of seconds after creation time
*
* @param sig signature handle.
Expand Down
1 change: 1 addition & 0 deletions include/rnp/rnp_err.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum {
RNP_ERROR_OUT_OF_MEMORY,
RNP_ERROR_SHORT_BUFFER,
RNP_ERROR_NULL_POINTER,
RNP_ERROR_NOT_FOUND,

/* Storage */
RNP_ERROR_ACCESS = 0x11000000,
Expand Down
8 changes: 8 additions & 0 deletions src/lib/ffi-priv-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ struct rnp_signature_handle_st {
bool new_sig;
};

struct rnp_sig_subpacket_st {
const pgp::pkt::sigsub::Raw ⊂

rnp_sig_subpacket_st(const pgp::pkt::sigsub::Raw &val) : sub(val)
{
}
};

struct rnp_recipient_handle_st {
rnp_ffi_t ffi;
pgp_key_id_t keyid;
Expand Down
106 changes: 99 additions & 7 deletions src/lib/rnp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,18 @@ ret_str_value(const char *str, char **res)
return RNP_SUCCESS;
}

static rnp_result_t
ret_vec_value(const std::vector<uint8_t> &vec, uint8_t **buf, size_t *buf_len)
{
*buf = (uint8_t *) calloc(1, vec.size());
if (!*buf) {
return RNP_ERROR_OUT_OF_MEMORY;

Check warning on line 553 in src/lib/rnp.cpp

View check run for this annotation

Codecov / codecov/patch

src/lib/rnp.cpp#L553

Added line #L553 was not covered by tests
}
memcpy(*buf, vec.data(), vec.size());
*buf_len = vec.size();
return RNP_SUCCESS;
}

static rnp_result_t
get_map_value(const id_str_pair *map, int val, char **res)
{
Expand Down Expand Up @@ -6650,6 +6662,92 @@ try {
}
FFI_GUARD

rnp_result_t
rnp_signature_subpacket_count(rnp_signature_handle_t handle, size_t *count)
try {
if (!handle || !count) {
return RNP_ERROR_NULL_POINTER;
}
*count = handle->sig->sig.subpkts.size();
return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_signature_subpacket_at(rnp_signature_handle_t handle,
size_t idx,
rnp_sig_subpacket_t * subpkt)
try {
if (!handle || !subpkt) {
return RNP_ERROR_NULL_POINTER;
}
if (idx >= handle->sig->sig.subpkts.size()) {
return RNP_ERROR_NOT_FOUND;
}
*subpkt = new rnp_sig_subpacket_st(*handle->sig->sig.subpkts[idx]);
return RNP_SUCCESS;
}
FFI_GUARD

Check warning on line 6690 in src/lib/rnp.cpp

View check run for this annotation

Codecov / codecov/patch

src/lib/rnp.cpp#L6690

Added line #L6690 was not covered by tests

rnp_result_t
rnp_signature_subpacket_find(rnp_signature_handle_t handle,
uint8_t type,
bool hashed,
size_t skip,
rnp_sig_subpacket_t * subpkt)
try {
if (!handle || !subpkt) {
return RNP_ERROR_NULL_POINTER;
}
auto idx = handle->sig->sig.find_subpkt(type, hashed, skip);
return rnp_signature_subpacket_at(handle, idx, subpkt);
}
FFI_GUARD

Check warning on line 6705 in src/lib/rnp.cpp

View check run for this annotation

Codecov / codecov/patch

src/lib/rnp.cpp#L6705

Added line #L6705 was not covered by tests

rnp_result_t
rnp_signature_subpacket_info(rnp_sig_subpacket_t subpkt,
uint8_t * type,
bool * hashed,
bool * critical)
try {
if (!subpkt) {
return RNP_ERROR_NULL_POINTER;

Check warning on line 6714 in src/lib/rnp.cpp

View check run for this annotation

Codecov / codecov/patch

src/lib/rnp.cpp#L6714

Added line #L6714 was not covered by tests
}
if (type) {
*type = subpkt->sub.raw_type();
}
if (hashed) {
*hashed = subpkt->sub.hashed();
}
if (critical) {
*critical = subpkt->sub.critical();
}
return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_signature_subpacket_data(rnp_sig_subpacket_t subpkt, uint8_t **data, size_t *size)
try {
if (!subpkt || !data || !size) {
return RNP_ERROR_NULL_POINTER;
}
auto &subdata = subpkt->sub.data();
if (!subdata.size()) {
return RNP_ERROR_BAD_STATE;

Check warning on line 6737 in src/lib/rnp.cpp

View check run for this annotation

Codecov / codecov/patch

src/lib/rnp.cpp#L6737

Added line #L6737 was not covered by tests
}
return ret_vec_value(subdata, data, size);
}
FFI_GUARD

rnp_result_t
rnp_signature_subpacket_destroy(rnp_sig_subpacket_t subpkt)
try {
delete subpkt;
return RNP_SUCCESS;
}
FFI_GUARD

rnp_result_t
rnp_signature_get_expiration(rnp_signature_handle_t handle, uint32_t *expires)
try {
Expand Down Expand Up @@ -8004,13 +8102,7 @@ static rnp_result_t
key_to_bytes(pgp_key_t *key, uint8_t **buf, size_t *buf_len)
{
auto vec = key->write_vec();
*buf = (uint8_t *) calloc(1, vec.size());
if (!*buf) {
return RNP_ERROR_OUT_OF_MEMORY;
}
memcpy(*buf, vec.data(), vec.size());
*buf_len = vec.size();
return RNP_SUCCESS;
return ret_vec_value(vec, buf, buf_len);
}

rnp_result_t
Expand Down
93 changes: 93 additions & 0 deletions src/tests/ffi-key-sig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2302,6 +2302,35 @@ TEST_F(rnp_tests, test_ffi_key_self_certification_features)
assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 2, &alg));
assert_string_equal(alg, "ZIP");
rnp_buffer_destroy(alg);
rnp_sig_subpacket_t subpkt = NULL;
assert_rnp_success(rnp_signature_subpacket_count(newsig, &count));
assert_int_equal(count, 10);
assert_rnp_success(rnp_signature_subpacket_at(newsig, 0, &subpkt));
uint8_t type = 0;
bool hashed = false;
bool critical = false;
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 27);
assert_true(hashed);
assert_false(critical);
uint8_t *data = NULL;
size_t size = 0;
assert_rnp_success(rnp_signature_subpacket_data(subpkt, &data, &size));
assert_int_equal(size, 1);
assert_int_equal(data[0], 3);
rnp_buffer_destroy(data);
rnp_signature_subpacket_destroy(subpkt);
assert_rnp_success(rnp_signature_subpacket_at(newsig, 9, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 16);
assert_false(hashed);
assert_false(critical);
assert_rnp_success(rnp_signature_subpacket_data(subpkt, &data, &size));
assert_int_equal(size, 8);
assert_int_equal(data[0], 0x23);
assert_int_equal(data[7], 0x27);
rnp_buffer_destroy(data);
rnp_signature_subpacket_destroy(subpkt);
rnp_signature_handle_destroy(newsig);
/* First newly added signature with defaults */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &newsig));
Expand Down Expand Up @@ -2371,6 +2400,70 @@ TEST_F(rnp_tests, test_ffi_key_self_certification_features)
assert_rnp_failure(rnp_signature_get_preferred_zalg(NULL, 0, &alg));
assert_rnp_failure(rnp_signature_get_preferred_zalg(newsig, 0, NULL));
assert_rnp_failure(rnp_signature_get_preferred_zalg(newsig, 0, &alg));

assert_rnp_failure(rnp_signature_subpacket_count(NULL, &count));
assert_rnp_failure(rnp_signature_subpacket_count(newsig, NULL));
assert_rnp_success(rnp_signature_subpacket_count(newsig, &count));
assert_int_equal(count, 3);
assert_rnp_failure(rnp_signature_subpacket_at(NULL, 0, &subpkt));
assert_rnp_failure(rnp_signature_subpacket_at(newsig, 0, NULL));
assert_int_equal(rnp_signature_subpacket_at(newsig, 20, &subpkt), RNP_ERROR_NOT_FOUND);
assert_rnp_success(rnp_signature_subpacket_at(newsig, 0, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, NULL, NULL, NULL));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, NULL, NULL));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, NULL, &hashed, NULL));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, NULL, NULL, &critical));
assert_int_equal(type, 33);
assert_true(hashed);
assert_false(critical);
assert_rnp_failure(rnp_signature_subpacket_data(NULL, &data, &size));
assert_rnp_failure(rnp_signature_subpacket_data(subpkt, NULL, &size));
assert_rnp_failure(rnp_signature_subpacket_data(subpkt, &data, NULL));
assert_rnp_success(rnp_signature_subpacket_data(subpkt, &data, &size));
assert_int_equal(size, 21);
assert_int_equal(data[0], 0x04);
assert_int_equal(data[1], 0xb5);
assert_int_equal(data[20], 0x27);
rnp_buffer_destroy(data);
rnp_signature_subpacket_destroy(subpkt);
assert_rnp_success(rnp_signature_subpacket_at(newsig, 1, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 2);
assert_true(hashed);
assert_false(critical);
assert_rnp_success(rnp_signature_subpacket_data(subpkt, &data, &size));
assert_int_equal(size, 4);
assert_int_equal(data[1], 0x06);
rnp_buffer_destroy(data);
rnp_signature_subpacket_destroy(subpkt);
assert_rnp_success(rnp_signature_subpacket_at(newsig, 2, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 16);
assert_false(hashed);
assert_false(critical);
assert_rnp_success(rnp_signature_subpacket_data(subpkt, &data, &size));
assert_int_equal(size, 8);
assert_int_equal(data[0], 0x23);
rnp_buffer_destroy(data);
rnp_signature_subpacket_destroy(subpkt);
assert_rnp_failure(rnp_signature_subpacket_find(NULL, 33, true, 0, &subpkt));
assert_rnp_failure(rnp_signature_subpacket_find(newsig, 33, true, 0, NULL));
assert_int_equal(rnp_signature_subpacket_find(newsig, 33, true, 1, &subpkt),
RNP_ERROR_NOT_FOUND);
assert_int_equal(rnp_signature_subpacket_find(newsig, 18, true, 0, &subpkt),
RNP_ERROR_NOT_FOUND);
assert_rnp_success(rnp_signature_subpacket_find(newsig, 33, true, 0, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 33);
assert_true(hashed);
assert_false(critical);
rnp_signature_subpacket_destroy(subpkt);
assert_rnp_success(rnp_signature_subpacket_find(newsig, 16, false, 0, &subpkt));
assert_rnp_success(rnp_signature_subpacket_info(subpkt, &type, &hashed, &critical));
assert_int_equal(type, 16);
assert_false(hashed);
assert_false(critical);
rnp_signature_subpacket_destroy(subpkt);
rnp_signature_handle_destroy(newsig);
/* Second newly added signature with customized parameters */
assert_rnp_success(rnp_uid_get_signature_at(uid, 2, &newsig));
Expand Down

0 comments on commit 27b1ab7

Please sign in to comment.