ENGINE-968: change ASN.1 representation of identities, ASN.1 map, test suite

ENGINE-968
positron 1 year ago
parent 840fa041f3
commit f89446ef06

@ -7,6 +7,225 @@
#include "pEp_internal.h"
#include "map_asn1.h"
/* Expand to a statement checking that the given expression evaluates to a
non-NULL result, first using an assert and then an explicit check in C. If
the check fails branch to the given label. */
#define CHECK_NON_NULLITY_OR_GOTO(expr, label) \
do \
{ \
assert(expr); \
if (! (expr)) \
goto label; \
} \
while (false)
/* Same as CHECK_NON_NULLITY_OR_GOTO, but in case of failure return the given
expression (evaluated only once after the check) instead of branching. */
#define CHECK_NON_NULLITY_OR_RETURN(expr, result) \
do \
{ \
assert(expr); \
if (! (expr)) \
return (result); \
} \
while (false)
/* Expand to a statement which:
- reallocates a new heap buffer of the given size, (as if with realloc),
updating the given pointer lvalue;
- jumps to the given label in case of allocation failure.
The expansion may evaluate parameters multiple times. */
#define ALLOCATE_OR_GOTO(lvalue_pointer, size, label) \
do \
{ \
/* Free any previous buffer, and reset to NULL. This is necessary \
for correct deallocation in case of allocation errors later. */ \
if ((lvalue_pointer) != NULL) { \
free (lvalue_pointer); \
lvalue_pointer = NULL; \
} \
(lvalue_pointer) = calloc (1, (size)); \
if ((lvalue_pointer) == NULL) \
goto label; \
} \
while (false)
PIdentity_t *PIdentity_from_Struct(
const pEp_identity *ident,
PIdentity_t *result
)
{
bool allocated = !result;
CHECK_NON_NULLITY_OR_RETURN (ident, NULL);
if (allocated)
result = (PIdentity_t *) calloc(1, sizeof(PIdentity_t));
CHECK_NON_NULLITY_OR_RETURN (result, NULL);
if (ident->address) {
int r = OCTET_STRING_fromBuf(&result->address, ident->address, -1);
if (r)
goto error;
}
if (! EMPTYSTR (ident->fpr)) {
ALLOCATE_OR_GOTO (result->fpr, sizeof (Hash_t), error);
if (OCTET_STRING_fromString(result->fpr, ident->fpr))
goto error;
}
if (ident->user_id) {
int r = OCTET_STRING_fromBuf(&result->user_id, ident->user_id, -1);
if (r)
goto error;
}
if (! EMPTYSTR (ident->username)) {
ALLOCATE_OR_GOTO (result->username, sizeof (PString_t), error);
int r = OCTET_STRING_fromBuf(result->username, ident->username, -1);
if (r)
goto error;
}
if (ident->comm_type != PEP_ct_unknown) {
result->comm_type = ident->comm_type;
}
ALLOCATE_OR_GOTO (result->lang, sizeof (ISO639_1_t), error);
if (! EMPTYSTR (ident->lang)) {
int r = OCTET_STRING_fromBuf(result->lang, ident->lang, 2);
assert(r == 0);
if(r != 0)
goto error;
}
else {
int r = OCTET_STRING_fromBuf(result->lang, "en", 2);
assert(r == 0);
if(r != 0)
goto error;
}
return result;
error:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PIdentity, result);
return NULL;
}
pEp_identity *PIdentity_to_Struct(PIdentity_t *ident, pEp_identity *result)
{
bool allocated = !result;
assert(ident);
if (!ident)
return NULL;
if (allocated)
result = new_identity(NULL, NULL, NULL, NULL);
CHECK_NON_NULLITY_OR_RETURN (result, NULL);
result->address = strndup((char *) ident->address.buf,
ident->address.size);
CHECK_NON_NULLITY_OR_GOTO (result->address, enomem);
if (ident->fpr && ! EMPTYSTR (ident->fpr->buf)) {
result->fpr = strndup((char *) ident->fpr->buf, ident->fpr->size);
CHECK_NON_NULLITY_OR_GOTO (result->fpr, enomem);
}
result->user_id = strndup((char *) ident->user_id.buf,
ident->user_id.size);
CHECK_NON_NULLITY_OR_GOTO (result->user_id, enomem);
if (ident->username && ! EMPTYSTR (ident->username->buf)) {
result->username = strndup((char *) ident->username->buf,
ident->username->size);
CHECK_NON_NULLITY_OR_GOTO (result->username, enomem);
}
result->comm_type = (PEP_comm_type) ident->comm_type;
if (ident->lang && ident->lang->size == 2) {
result->lang[0] = ident->lang->buf[0];
result->lang[1] = ident->lang->buf[1];
result->lang[2] = 0;
}
return result;
enomem:
if (allocated)
free_identity(result);
return NULL;
}
PIdentityList_t *PIdentityList_from_identity_list(
const identity_list *list,
PIdentityList_t *result
)
{
bool allocated = !result;
if (!(list && list->ident))
return NULL;
if (allocated) {
result = (PIdentityList_t *) calloc(1, sizeof(PIdentityList_t));
assert(result);
if (!result)
return NULL;
}
else {
asn_sequence_empty(result);
}
for (const identity_list *l = list; l && l->ident; l=l->next) {
PIdentity_t *ident = PIdentity_from_Struct(l->ident, NULL);
if (ASN_SEQUENCE_ADD(&result->list, ident)) {
ASN_STRUCT_FREE(asn_DEF_PIdentity, ident);
goto enomem;
}
}
return result;
enomem:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PIdentityList, result);
return NULL;
}
identity_list *PIdentityList_to_identity_list(PIdentityList_t *list, identity_list *result)
{
bool allocated = !result;
assert(list);
if (!list)
return NULL;
if (allocated)
result = new_identity_list(NULL);
if (!result)
return NULL;
identity_list *r = result;
for (int i=0; i<list->list.count; i++) {
pEp_identity *ident = PIdentity_to_Struct(list->list.array[i], NULL);
r = identity_list_add(r, ident);
if (!r)
goto enomem;
}
return result;
enomem:
if (allocated)
free_identity_list(result);
return NULL;
}
Identity_t *Identity_from_Struct(
const pEp_identity *ident,
Identity_t *result
@ -51,7 +270,7 @@ Identity_t *Identity_from_Struct(
result->comm_type = ident->comm_type;
}
if (ident->lang[0]) {
if (! EMPTYSTR(ident->lang)) {
int r = OCTET_STRING_fromBuf(&result->lang, ident->lang, 2);
assert(r == 0);
if(r != 0)
@ -675,10 +894,10 @@ ASN1Message_t *ASN1Message_from_message(
if (!msg->from) // from is not optional
goto enomem;
Identity_from_Struct(msg->from, &result->from);
PIdentity_from_Struct(msg->from, &result->from);
if (msg->to && msg->to->ident) {
IdentityList_t *l = IdentityList_from_identity_list(msg->to, NULL);
PIdentityList_t *l = PIdentityList_from_identity_list(msg->to, NULL);
if (!l)
goto enomem;
@ -686,7 +905,7 @@ ASN1Message_t *ASN1Message_from_message(
}
if (msg->cc && msg->cc->ident) {
IdentityList_t *l = IdentityList_from_identity_list(msg->cc, NULL);
PIdentityList_t *l = PIdentityList_from_identity_list(msg->cc, NULL);
if (!l)
goto enomem;
@ -694,7 +913,7 @@ ASN1Message_t *ASN1Message_from_message(
}
if (msg->bcc && msg->bcc->ident) {
IdentityList_t *l = IdentityList_from_identity_list(msg->bcc, NULL);
PIdentityList_t *l = PIdentityList_from_identity_list(msg->bcc, NULL);
if (!l)
goto enomem;
@ -702,7 +921,7 @@ ASN1Message_t *ASN1Message_from_message(
}
if (msg->recv_by) {
Identity_t *i = Identity_from_Struct(msg->recv_by, NULL);
PIdentity_t *i = PIdentity_from_Struct(msg->recv_by, NULL);
if (!i)
goto enomem;
@ -710,7 +929,7 @@ ASN1Message_t *ASN1Message_from_message(
}
if (msg->reply_to && msg->reply_to->ident) {
IdentityList_t *l = IdentityList_from_identity_list(msg->reply_to, NULL);
PIdentityList_t *l = PIdentityList_from_identity_list(msg->reply_to, NULL);
if (!l)
goto enomem;
@ -920,12 +1139,12 @@ message *ASN1Message_to_message(
}
// from is mandatory
result->from = Identity_to_Struct(&msg->from, NULL);
result->from = PIdentity_to_Struct(&msg->from, NULL);
if (!result->from)
goto enomem;
if (msg->to) {
identity_list *il = IdentityList_to_identity_list(msg->to, NULL);
identity_list *il = PIdentityList_to_identity_list(msg->to, NULL);
if (!il)
goto enomem;
@ -933,7 +1152,7 @@ message *ASN1Message_to_message(
}
if (msg->cc) {
identity_list *il = IdentityList_to_identity_list(msg->cc, NULL);
identity_list *il = PIdentityList_to_identity_list(msg->cc, NULL);
if (!il)
goto enomem;
@ -941,7 +1160,7 @@ message *ASN1Message_to_message(
}
if (msg->bcc) {
identity_list *il = IdentityList_to_identity_list(msg->bcc, NULL);
identity_list *il = PIdentityList_to_identity_list(msg->bcc, NULL);
if (!il)
goto enomem;
@ -949,7 +1168,7 @@ message *ASN1Message_to_message(
}
if (msg->recv_by) {
pEp_identity *i = Identity_to_Struct(msg->recv_by, NULL);
pEp_identity *i = PIdentity_to_Struct(msg->recv_by, NULL);
if (!i)
goto enomem;
@ -957,7 +1176,7 @@ message *ASN1Message_to_message(
}
if (msg->reply_to) {
identity_list *il = IdentityList_to_identity_list(msg->reply_to, NULL);
identity_list *il = PIdentityList_to_identity_list(msg->reply_to, NULL);
if (!il)
goto enomem;

@ -15,6 +15,85 @@ extern "C" {
#endif
/* For compatibility reasons we have PIdentity as a distinct struct from
Identity. The difference is that PIdentity has some optional fields, notably
fpr.
Some functionality is replicated for each struct kind. */
/**
* <!-- PIdentity_from_Struct() -->
*
* @brief Convert pEp_identity into ASN.1 PIdentity_t
*
* @param ident[in] pEp_identity to convert
* @param result[in,out] PIdentity_t to update or NULL to alloc a new one
*
* @retval pointer to updated or allocated result
*
* @warning if a new struct is allocated, the ownership goes to the caller
*
*/
PIdentity_t *PIdentity_from_Struct(
const pEp_identity *ident,
PIdentity_t *result
);
/**
* <!-- PIdentity_to_Struct() -->
*
* @brief Convert ASN.1 PIdentity_t into pEp_identity
*
* @param ident[in] PIdentity_t to convert
* @param result[inout] pEp_identity to update or NULL to alloc a new one
*
* @retval pointer to updated or allocated result
*
* @warning if a new struct is allocated, the ownership goes to the caller
*
*/
pEp_identity *PIdentity_to_Struct(PIdentity_t *ident, pEp_identity *result);
/**
* <!-- PIdentityList_from_identity_list() -->
*
* @brief Convert identity_list_t into ASN.1 PIdentityList_t
*
* @param list[in] identity_list to convert
* @param result[inout] PIdentityList_t to update or NULL to alloc a new one
*
* @retval pointer to updated or allocated result
*
* @warning if a new struct is allocated, the ownership goes to the caller
*
*/
PIdentityList_t *PIdentityList_from_identity_list(
const identity_list *list,
PIdentityList_t *result
);
/**
* <!-- PIdentityList_to_identity_list() -->
*
* @brief Convert ASN.1 PIdentityList_t to identity_list_t
*
* @param list[in] ASN.1 PIdentityList_t to convert
* @param result[inout] identity_list_t to update or NULL to alloc a new one
*
* @retval pointer to updated or allocated result
*
* @warning if a new struct is allocated, the ownership goes to the caller
*
*/
identity_list *PIdentityList_to_identity_list(PIdentityList_t *list, identity_list *result);
/**
* <!-- Identity_from_Struct() -->
*

@ -1910,6 +1910,7 @@ TEST_F(GroupEncryptionTest, check_protocol_group_dissolve_send) {
// First, make sure that's who's in our group, eh?
member_list* members = NULL;
status = retrieve_active_member_list(session, group_ident, &members);
ASSERT_NE (members, nullptr);
const char* member_names[] = {member_1_name, member_2_name, member_4_name};
const char* member_addrs[] = {member_1_address, member_2_address, member_4_address};
const char* member_fprs[] = {member_1_fpr, member_2_fpr, member_4_fpr};

@ -7,6 +7,8 @@
#include "TestUtilities.h"
#include "TestConstants.h"
#include "Engine.h"
#include "map_asn1.h"
#include "message_codec.h"
#include <gtest/gtest.h>
@ -88,6 +90,120 @@ namespace {
} // namespace
TEST_F(IdentEncFormatTest, check_identity_empty_fingerprint) {
/* For reasons of backward-compatibility we cannot support an identity with
no fingerprint (in the ASN.1 encoding), but we can support an identity
with an empty fingerprint -- In the engine C code in practice we also
accept NULL.
This test case is derived from check_ident_enc_format_unspecified , but
omits the format test at the end and, crucially, uses an empty FPR for
Alice. */
ASSERT_TRUE(slurp_and_import_key(session, carol_filename));
stringlist_t* found_key = NULL;
PEP_STATUS status = find_keys(session, carol_fpr, &found_key);
ASSERT_OK;
ASSERT_NOTNULL(found_key);
ASSERT_NOTNULL(found_key->value);
ASSERT_STREQ(found_key->value, carol_fpr);
ASSERT_NULL(found_key->next);
const char* my_fpr = carol_fpr;
const char* my_name = "Carol Peril";
const char* my_address = "carol_peril@darthmama.cool";
pEp_identity* my_ident = new_identity(my_address, my_fpr, PEP_OWN_USERID, my_name);
status = set_own_key(session, my_ident, my_fpr);
ASSERT_OK;
// Set up "to"
ASSERT_TRUE(slurp_and_import_key(session, alice_pub_filename));
const char* to_fpr = NULL; /* And not alice_fpr: here I did "the move". */
const char* to_name = "Alice Malice";
const char* to_address = "alice_malice@darthmama.cool";
pEp_identity* to_ident = new_identity(to_address, to_fpr, "ALICE", to_name);
status = set_identity(session, to_ident);
ASSERT_OK;
message* msg = new_message(PEP_dir_outgoing);
msg->from = my_ident;
msg->to = new_identity_list(to_ident);
msg->shortmsg = strdup("This is an exciting message from Carol!");
msg->longmsg = strdup("Not\nVery\nExciting\n");
std::cout << "OK-A 50000\n";
/* Notice that encryption is supposed to fail here... */
message* enc_msg = NULL;
status = encrypt_message(session, msg, NULL, &enc_msg, PEP_enc_auto, 0);
ASSERT_EQ (status, PEP_UNENCRYPTED);
ASSERT_NULL(enc_msg); /* ...this is expected, since encryption failed. */
std::cout << "OK-A 70000\n";
free_message(msg);
free_stringlist(found_key);
}
/* This is a helper for testCaseAsnEncodeMessageFingerprint which is a helper
for check_ident_non_empty_fingerprint_encoding and
check_ident_empty_fingerprint_encoding . */
static char *pString(const char *pstrIn)
{
const size_t maxSize = 256;
size_t inputSize = strnlen(pstrIn, maxSize);
char *pstrResult = (char *) malloc(inputSize + 1);
strncpy(pstrResult, pstrIn, inputSize + 1);
pstrResult[inputSize] = '\0';
return pstrResult;
}
/* This is a helper for check_ident_non_empty_fingerprint_encoding and
check_ident_empty_fingerprint_encoding . */
static bool testCaseAsnEncodeMessageFingerprint(bool useFingerprint)
{
pEp_identity *from = new_identity(pString("blah1@example.com"),
useFingerprint ? pString("0E12343434343434343434EAB3484343434343434") : NULL,
pString("user_id_1"),
pString("user_name_1"));
pEp_identity *to = new_identity(pString("blah2@example.com"),
useFingerprint ? pString("123434343434343C3434343434343734349A34344") : NULL,
pString("user_id_2"),
pString("user_name_2"));
message *msg = new_message(PEP_dir_outgoing);
msg->from = from;
msg->to = new_identity_list(to);
msg->longmsg = pString("some text");
ASN1Message_t *asn1Message = ASN1Message_from_message(msg, NULL, true, 0);
if (asn1Message == NULL) {
free_message(msg);
return false;
}
char *msgBytes = NULL;
size_t msgBytesSze = 0;
PEP_STATUS status = encode_ASN1Message_message(asn1Message, &msgBytes, &msgBytesSze);
if (status != PEP_STATUS_OK) {
free_message(msg);
return false;
}
free_message(msg);
return true;
}
TEST_F(IdentEncFormatTest, check_ident_non_empty_fingerprint_encoding) {
ASSERT_EQ(! ! testCaseAsnEncodeMessageFingerprint(true), true);
}
TEST_F(IdentEncFormatTest, check_ident_empty_fingerprint_encoding) {
ASSERT_EQ(! ! testCaseAsnEncodeMessageFingerprint(false), true);
}
TEST_F(IdentEncFormatTest, check_ident_enc_format_unspecified) {
ASSERT_TRUE(slurp_and_import_key(session, carol_filename));
stringlist_t* found_key = NULL;

Loading…
Cancel
Save