Browse Source

merged heads

add_key_notification
parent
commit
f34f439d68
3 changed files with 177 additions and 69 deletions
  1. +150
    -48
      src/pgp_sequoia.c
  2. +26
    -21
      test/README.md
  3. +1
    -0
      test/src/test_util.cc

+ 150
- 48
src/pgp_sequoia.c View File

@ -173,17 +173,15 @@ int email_cmp(void *cookie, int a_len, const void *a, int b_len, const void *b)
pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
char *a_email = NULL;
pgp_user_id_email_normalized(NULL, a_userid, &a_email);
if (!a_email)
pgp_user_id_uri(NULL, a_userid, &a_email);
char *a_address = NULL;
pgp_user_id_address_normalized(NULL, a_userid, &a_address);
if (!a_address)
pgp_user_id_other(NULL, a_userid, &a_address);
char *b_address = NULL;
pgp_user_id_address_normalized(NULL, b_userid, &b_address);
if (!b_address)
pgp_user_id_other(NULL, b_userid, &b_address);
char *b_email = NULL;
pgp_user_id_email_normalized(NULL, b_userid, &b_email);
if (!b_email)
pgp_user_id_uri(NULL, b_userid, &b_email);
pgp_packet_free(a_userid);
pgp_packet_free(b_userid);
@ -192,24 +190,24 @@ int email_cmp(void *cookie, int a_len, const void *a, int b_len, const void *b)
// first string is less than, equal to, or greater than the
// second, respectively.
int result;
if (!a_address && !b_address)
if (!a_email && !b_email)
result = 0;
else if (!a_address)
else if (!a_email)
result = -1;
else if (!b_address)
else if (!b_email)
result = 1;
else
result = strcmp(a_address, b_address);
result = strcmp(a_email, b_email);
if (true) {
T("'%s' %s '%s'",
a_address,
a_email,
result == 0 ? "==" : result < 0 ? "<" : ">",
b_address);
b_email);
}
free(a_address);
free(b_address);
free(a_email);
free(b_email);
return result;
}
@ -244,15 +242,17 @@ PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
// Create the DB and initialize it.
size_t path_size = strlen(home_env) + sizeof(PEP_KEYS_PATH);
char *path = (char *) calloc(1, path_size);
char *path = (char *) calloc(path_size, 1);
assert(path);
if (!path)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
int r = snprintf(path, path_size, "%s" PEP_KEYS_PATH, home_env);
assert(r >= 0 && r < path_size);
if (r < 0)
if (r < 0) {
free(path);
ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
}
int sqlite_result;
sqlite_result = sqlite3_open_v2(path,
@ -790,7 +790,7 @@ static PEP_STATUS tpk_save(PEP_SESSION session, pgp_tpk_t tpk,
pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
pgp_status = pgp_tsk_serialize(&err, tsk, writer);
pgp_tsk_free(tsk);
//pgp_writer_free(writer);
pgp_writer_free(writer);
if (pgp_status != 0)
ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Serializing TPK");
@ -856,7 +856,12 @@ static PEP_STATUS tpk_save(PEP_SESSION session, pgp_tpk_t tpk,
pgp_packet_t userid = pgp_user_id_new (user_id_value);
pgp_user_id_name(NULL, userid, &name);
pgp_user_id_address_or_other(NULL, userid, &email);
// Try to get the normalized address.
pgp_user_id_email_normalized(NULL, userid, &email);
if (! email)
// Ok, it's not a proper RFC 2822 name-addr. Perhaps it
// is a URI.
pgp_user_id_uri(NULL, userid, &email);
pgp_packet_free(userid);
free(user_id_value);
@ -1238,7 +1243,7 @@ check_signatures_cb(void *cookie_opaque, pgp_message_structure_t structure)
// Make sure the TPK is not revoked, it's
// creation time is <= now, and it hasn't
// expired.
pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
bool revoked = (pgp_revocation_status_variant(rs)
== PGP_REVOCATION_STATUS_REVOKED);
pgp_revocation_status_free(rs);
@ -1246,7 +1251,7 @@ check_signatures_cb(void *cookie_opaque, pgp_message_structure_t structure)
T("TPK %s is revoked.", primary_fpr_str);
good = false;
cookie->good_but_revoked ++;
} else if (! pgp_tpk_alive(tpk)) {
} else if (! pgp_tpk_alive(tpk, 0)) {
T("TPK %s is not alive.", primary_fpr_str);
good = false;
cookie->good_but_expired ++;
@ -1271,7 +1276,7 @@ check_signatures_cb(void *cookie_opaque, pgp_message_structure_t structure)
primary_fpr_str, keyid_str);
good = false;
cookie->good_but_revoked ++;
} else if (! pgp_signature_key_alive(sig, key)) {
} else if (! pgp_signature_key_alive(sig, key, 0)) {
T("TPK %s's signing key %s is expired.",
primary_fpr_str, keyid_str);
good = false;
@ -1669,6 +1674,8 @@ PEP_STATUS pgp_sign_only(
ws = pgp_signer_new_detached(&err, ws, &signer, 1, 0);
if (!ws)
ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
// pgp_signer_new_detached consumes signer.
signer = NULL;
pgp_status_t write_status =
pgp_writer_stack_write_all (&err, ws,
@ -1690,7 +1697,11 @@ PEP_STATUS pgp_sign_only(
out:
pgp_signer_free (signer);
pgp_key_pair_free (signing_keypair);
// XXX: pgp_key_pair_as_signer is only supposed to reference
// signing_keypair, but it consumes it. If this is fixed, this
// will become a leak.
//
//pgp_key_pair_free (signing_keypair);
pgp_tpk_key_iter_free (iter);
pgp_tpk_free(signer_tpk);
@ -1704,8 +1715,16 @@ static PEP_STATUS pgp_encrypt_sign_optional(
{
PEP_STATUS status = PEP_STATUS_OK;
pgp_error_t err = NULL;
int keys_count = 0;
pgp_tpk_t *keys = NULL;
int recipient_tpk_count = 0;
pgp_tpk_t *recipient_tpks = NULL;
int recipient_count = 0;
int recipient_alloc = 0;
pgp_recipient_t *recipients = NULL;
int recipient_keys_count = 0;
pgp_key_t *recipient_keys = NULL;
pgp_tpk_t signer_tpk = NULL;
pgp_writer_stack_t ws = NULL;
pgp_tpk_key_iter_t iter = NULL;
@ -1722,18 +1741,82 @@ static PEP_STATUS pgp_encrypt_sign_optional(
*ctext = NULL;
*csize = 0;
keys = calloc(stringlist_length(keylist), sizeof(*keys));
if (keys == NULL)
int keylist_len = stringlist_length(keylist);
// We don't need to worry about extending recipient_tpks, because
// there will be at most KEYLIST_LEN tpks, which we allocate up
// front.
recipient_tpks = calloc(keylist_len, sizeof(*recipient_tpks));
if (recipient_tpks == NULL)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
// Because there may be multiple encryption keys per TPK, we may
// need to extend recipient_keys and recipients.
recipient_alloc = keylist_len;
recipient_keys = calloc(recipient_alloc, sizeof(*recipient_keys));
if (recipient_keys == NULL)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
recipients = calloc(recipient_alloc, sizeof(*recipients));
if (recipients == NULL)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
// Get the keys for the recipients.
const stringlist_t *_keylist;
for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
assert(_keylist->value);
pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(_keylist->value);
status = tpk_find_by_fpr(session, pgp_fpr, false, &keys[keys_count ++], NULL);
pgp_fingerprint_free(pgp_fpr);
ERROR_OUT(NULL, status, "Looking up key for recipient '%s'", _keylist->value);
pgp_tpk_t tpk;
status = tpk_find_by_fpr_hex(session, _keylist->value,
false, &tpk, NULL);
// We couldn't find a key for this recipient.
ERROR_OUT(NULL, status,
"Looking up key for recipient '%s'", _keylist->value);
recipient_tpks[recipient_tpk_count ++] = tpk;
// Collect all of the keys that have the encryption for
// transport capability.
pgp_tpk_key_iter_t iter = pgp_tpk_key_iter_valid(tpk);
if (! iter)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
pgp_tpk_key_iter_encrypting_capable_for_transport(iter);
pgp_key_t key;
while ((key = pgp_tpk_key_iter_next (iter, NULL, NULL))) {
assert(recipient_count == recipient_keys_count);
if (recipient_count == recipient_alloc) {
assert(recipient_alloc > 0);
recipient_alloc *= 2;
void *t = reallocarray(recipient_keys, recipient_alloc,
sizeof(*recipient_keys));
if (! t)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
recipient_keys = t;
t = reallocarray(recipients, recipient_alloc,
sizeof(*recipients));
if (! t)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
recipients = t;
}
// pgp_recipient_new consumes the passed key id, but it
// only references key (i.e., we still have to free key).
pgp_keyid_t keyid = pgp_key_keyid(key);
if (! key)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
key = pgp_key_clone(key);
if (! key)
ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
recipient_keys[recipient_keys_count++] = key;
recipients[recipient_count++] = pgp_recipient_new(keyid, key);
}
pgp_tpk_key_iter_free(iter);
}
if (sign) {
@ -1750,11 +1833,14 @@ static PEP_STATUS pgp_encrypt_sign_optional(
ws = pgp_writer_stack_message(writer);
ws = pgp_encryptor_new (&err, ws,
NULL, 0, keys, keys_count,
PGP_ENCRYPTION_MODE_FOR_TRANSPORT, 0);
NULL, 0, recipients, recipient_count,
0, 0);
if (!ws)
ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up encryptor");
// pgp_encrypt_new consumes the recipients (but not the keys).
recipient_count = 0;
if (sign) {
iter = pgp_tpk_key_iter_valid(signer_tpk);
pgp_tpk_key_iter_signing_capable (iter);
@ -1778,6 +1864,8 @@ static PEP_STATUS pgp_encrypt_sign_optional(
ws = pgp_signer_new(&err, ws, &signer, 1, 0);
if (!ws)
ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
// pgp_signer_new consumes signer.
signer = NULL;
}
ws = pgp_literal_writer_new (&err, ws);
@ -1809,13 +1897,23 @@ static PEP_STATUS pgp_encrypt_sign_optional(
out:
pgp_signer_free (signer);
pgp_key_pair_free (signing_keypair);
// XXX: pgp_key_pair_as_signer is only supposed to reference
// signing_keypair, but it consumes it. If this is fixed, this
// will become a leak.
//
// pgp_key_pair_free (signing_keypair);
pgp_tpk_key_iter_free (iter);
pgp_tpk_free(signer_tpk);
for (int i = 0; i < keys_count; i ++)
pgp_tpk_free(keys[i]);
free(keys);
for (int i = 0; i < recipient_count; i ++)
pgp_recipient_free(recipients[i]);
free(recipients);
for (int i = 0; i < recipient_keys_count; i ++)
pgp_key_free(recipient_keys[i]);
free(recipient_keys);
for (int i = 0; i < recipient_tpk_count; i ++)
pgp_tpk_free(recipient_tpks[i]);
free(recipient_tpks);
T("-> %s", pEp_status_to_string(status));
return status;
@ -2267,7 +2365,7 @@ static stringpair_list_t *add_key(PEP_SESSION session,
bool revoked = false;
// Don't add revoked keys to the keyinfo_list.
if (keyinfo_list) {
pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
pgp_revocation_status_free(rs);
if (rsv == PGP_REVOCATION_STATUS_REVOKED)
@ -2469,7 +2567,7 @@ PEP_STATUS pgp_renew_key(
status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
ERROR_OUT(NULL, status, "Looking up '%s'", fpr);
uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary(tpk));
uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary_key(tpk));
if (creation_time > t)
// The creation time is after the expiration time!
ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
@ -2507,6 +2605,10 @@ PEP_STATUS pgp_renew_key(
out:
pgp_signer_free (signer);
// XXX: pgp_key_pair_as_signer is only supposed to reference
// signing_keypair, but it consumes it. If this is fixed, this
// will become a leak.
//
pgp_key_pair_free (keypair);
pgp_tpk_key_iter_free (iter);
pgp_tpk_free(tpk);
@ -2555,7 +2657,7 @@ PEP_STATUS pgp_revoke_key(
if (! tpk)
ERROR_OUT(err, PEP_UNKNOWN_ERROR, "setting expiration");
assert(pgp_revocation_status_variant(pgp_tpk_revocation_status(tpk))
assert(pgp_revocation_status_variant(pgp_tpk_revoked(tpk, 0))
== PGP_REVOCATION_STATUS_REVOKED);
status = tpk_save(session, tpk, NULL);
@ -2575,7 +2677,7 @@ PEP_STATUS pgp_revoke_key(
static void _pgp_key_expired(pgp_tpk_t tpk, const time_t when, bool* expired)
{
// Is the TPK live?
*expired = !pgp_tpk_alive_at(tpk, when);
*expired = !pgp_tpk_alive(tpk, when);
#ifdef TRACING
{
@ -2633,7 +2735,7 @@ static void _pgp_key_expired(pgp_tpk_t tpk, const time_t when, bool* expired)
out:
// Er, this might be problematic in terms of internal vs. external in log. FIXME?
T("(%s) -> %s (expired: %d)", fpr, pEp_status_to_string(status), *expired);
T(" -> expired: %d", *expired);
return;
}
@ -2680,7 +2782,7 @@ PEP_STATUS pgp_key_revoked(PEP_SESSION session, const char *fpr, bool *revoked)
pgp_fingerprint_free(pgp_fpr);
ERROR_OUT(NULL, status, "Looking up %s", fpr);
pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
*revoked = pgp_revocation_status_variant(rs) == PGP_REVOCATION_STATUS_REVOKED;
pgp_revocation_status_free (rs);
pgp_tpk_free(tpk);
@ -2724,7 +2826,7 @@ PEP_STATUS pgp_get_key_rating(
// goto out;
// }
pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
pgp_revocation_status_free(rs);
if (rsv == PGP_REVOCATION_STATUS_REVOKED) {
@ -2798,7 +2900,7 @@ PEP_STATUS pgp_key_created(PEP_SESSION session, const char *fpr, time_t *created
pgp_fingerprint_free(pgp_fpr);
ERROR_OUT(NULL, status, "Looking up %s", fpr);
pgp_key_t k = pgp_tpk_primary(tpk);
pgp_key_t k = pgp_tpk_primary_key(tpk);
*created = pgp_key_creation_time(k);
pgp_tpk_free(tpk);


+ 26
- 21
test/README.md View File

@ -41,27 +41,29 @@ anyway and who am I to judge?
##### Debian and Ubuntu (and derivatives)
Thanks to Erik Smistad for this starting point (condensed from [Getting Started
with Google Test On
Ubuntu](https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/)):
1. Install the packages `cmake` and `libgtest-dev` from the repository. This
will install the gtest source files to `/usr/src/gtest`. You'll still need to
compile the code and link the library files to be able to use them.
2. Compile the source files:
```
cd /usr/src/gtest
sudo cmake CMakeLists.txt
sudo make
```
3. Copy/symlink the libraries to the library location of your choice (here,
it's `/usr/lib`, hence the `sudo`, but as long as it's in your library path,
it shouldn't matter where you stick it):
```
sudo cp *.a /usr/lib
```
Using the libgtest-dev is easy, but not straightforward.
Unfortunately, the version of google test in Debian Buster is too old:
it's version 1.8 and we require version 1.9. Version 1.9 is available
in Debian Testing, but it is built with g++ 9.0, which is ABI
incompatible with binaries built with g++ 8.0, which is in Debian
stable. Specifically, gcc has changed the semantics of std::string
with C++11 and using g++ 8.0 results in the errors like the following:
undefined reference to `std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream()'
It's possible to install g++ 9.0 from testing to get the test suite
working, but that breaks other things (at least for me -Neal).
Instead, the easiest thing to do it to rebuild gtest for Debian
Stable. This is straightforward:
$ sudo apt install build-essential cmake debhelper
$ apt source -t testing libgtest-dev
$ cd googletest-1.9.0.20190831
$ dpkg-buildpackage -us -uc
...
$ sudo dpkg -i googletest_1.9.0.20190831-1_amd64.deb libgtest-dev_1.9.0.20190831-1_amd64.deb
That's it.
##### MacOS
@ -197,6 +199,9 @@ have found a dastardly bug in the engine, but it can also be a test issue.
gdb --args ./EngineTests --gtest_filter=TestSuiteName.test_function_name
```
When debugging a failing test, use '--gtest_break_on_failure' to have
gtest automatically break into the debugger where the assertion fails.
# Creating new tests
Script next on the agenda...


+ 1
- 0
test/src/test_util.cc View File

@ -13,6 +13,7 @@
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>


Loading…
Cancel
Save