1.1 --- a/src/pgp_sequoia.c Wed Nov 20 16:11:25 2019 +0100
1.2 +++ b/src/pgp_sequoia.c Mon Nov 25 11:00:36 2019 +0100
1.3 @@ -173,17 +173,15 @@
1.4 pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
1.5 pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
1.6
1.7 - T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
1.8 -
1.9 - char *a_address = NULL;
1.10 - pgp_user_id_address_normalized(NULL, a_userid, &a_address);
1.11 - if (!a_address)
1.12 - pgp_user_id_other(NULL, a_userid, &a_address);
1.13 -
1.14 - char *b_address = NULL;
1.15 - pgp_user_id_address_normalized(NULL, b_userid, &b_address);
1.16 - if (!b_address)
1.17 - pgp_user_id_other(NULL, b_userid, &b_address);
1.18 + char *a_email = NULL;
1.19 + pgp_user_id_email_normalized(NULL, a_userid, &a_email);
1.20 + if (!a_email)
1.21 + pgp_user_id_uri(NULL, a_userid, &a_email);
1.22 +
1.23 + char *b_email = NULL;
1.24 + pgp_user_id_email_normalized(NULL, b_userid, &b_email);
1.25 + if (!b_email)
1.26 + pgp_user_id_uri(NULL, b_userid, &b_email);
1.27
1.28 pgp_packet_free(a_userid);
1.29 pgp_packet_free(b_userid);
1.30 @@ -192,24 +190,24 @@
1.31 // first string is less than, equal to, or greater than the
1.32 // second, respectively.
1.33 int result;
1.34 - if (!a_address && !b_address)
1.35 + if (!a_email && !b_email)
1.36 result = 0;
1.37 - else if (!a_address)
1.38 + else if (!a_email)
1.39 result = -1;
1.40 - else if (!b_address)
1.41 + else if (!b_email)
1.42 result = 1;
1.43 else
1.44 - result = strcmp(a_address, b_address);
1.45 + result = strcmp(a_email, b_email);
1.46
1.47 if (true) {
1.48 T("'%s' %s '%s'",
1.49 - a_address,
1.50 + a_email,
1.51 result == 0 ? "==" : result < 0 ? "<" : ">",
1.52 - b_address);
1.53 + b_email);
1.54 }
1.55
1.56 - free(a_address);
1.57 - free(b_address);
1.58 + free(a_email);
1.59 + free(b_email);
1.60
1.61 return result;
1.62 }
1.63 @@ -244,15 +242,17 @@
1.64
1.65 // Create the DB and initialize it.
1.66 size_t path_size = strlen(home_env) + sizeof(PEP_KEYS_PATH);
1.67 - char *path = (char *) calloc(1, path_size);
1.68 + char *path = (char *) calloc(path_size, 1);
1.69 assert(path);
1.70 if (!path)
1.71 ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.72
1.73 int r = snprintf(path, path_size, "%s" PEP_KEYS_PATH, home_env);
1.74 assert(r >= 0 && r < path_size);
1.75 - if (r < 0)
1.76 + if (r < 0) {
1.77 + free(path);
1.78 ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
1.79 + }
1.80
1.81 int sqlite_result;
1.82 sqlite_result = sqlite3_open_v2(path,
1.83 @@ -790,7 +790,7 @@
1.84 pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
1.85 pgp_status = pgp_tsk_serialize(&err, tsk, writer);
1.86 pgp_tsk_free(tsk);
1.87 - //pgp_writer_free(writer);
1.88 + pgp_writer_free(writer);
1.89 if (pgp_status != 0)
1.90 ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Serializing TPK");
1.91
1.92 @@ -856,7 +856,12 @@
1.93
1.94 pgp_packet_t userid = pgp_user_id_new (user_id_value);
1.95 pgp_user_id_name(NULL, userid, &name);
1.96 - pgp_user_id_address_or_other(NULL, userid, &email);
1.97 + // Try to get the normalized address.
1.98 + pgp_user_id_email_normalized(NULL, userid, &email);
1.99 + if (! email)
1.100 + // Ok, it's not a proper RFC 2822 name-addr. Perhaps it
1.101 + // is a URI.
1.102 + pgp_user_id_uri(NULL, userid, &email);
1.103 pgp_packet_free(userid);
1.104 free(user_id_value);
1.105
1.106 @@ -1238,7 +1243,7 @@
1.107 // Make sure the TPK is not revoked, it's
1.108 // creation time is <= now, and it hasn't
1.109 // expired.
1.110 - pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
1.111 + pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
1.112 bool revoked = (pgp_revocation_status_variant(rs)
1.113 == PGP_REVOCATION_STATUS_REVOKED);
1.114 pgp_revocation_status_free(rs);
1.115 @@ -1246,7 +1251,7 @@
1.116 T("TPK %s is revoked.", primary_fpr_str);
1.117 good = false;
1.118 cookie->good_but_revoked ++;
1.119 - } else if (! pgp_tpk_alive(tpk)) {
1.120 + } else if (! pgp_tpk_alive(tpk, 0)) {
1.121 T("TPK %s is not alive.", primary_fpr_str);
1.122 good = false;
1.123 cookie->good_but_expired ++;
1.124 @@ -1271,7 +1276,7 @@
1.125 primary_fpr_str, keyid_str);
1.126 good = false;
1.127 cookie->good_but_revoked ++;
1.128 - } else if (! pgp_signature_key_alive(sig, key)) {
1.129 + } else if (! pgp_signature_key_alive(sig, key, 0)) {
1.130 T("TPK %s's signing key %s is expired.",
1.131 primary_fpr_str, keyid_str);
1.132 good = false;
1.133 @@ -1669,6 +1674,8 @@
1.134 ws = pgp_signer_new_detached(&err, ws, &signer, 1, 0);
1.135 if (!ws)
1.136 ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
1.137 + // pgp_signer_new_detached consumes signer.
1.138 + signer = NULL;
1.139
1.140 pgp_status_t write_status =
1.141 pgp_writer_stack_write_all (&err, ws,
1.142 @@ -1690,7 +1697,11 @@
1.143
1.144 out:
1.145 pgp_signer_free (signer);
1.146 - pgp_key_pair_free (signing_keypair);
1.147 + // XXX: pgp_key_pair_as_signer is only supposed to reference
1.148 + // signing_keypair, but it consumes it. If this is fixed, this
1.149 + // will become a leak.
1.150 + //
1.151 + //pgp_key_pair_free (signing_keypair);
1.152 pgp_tpk_key_iter_free (iter);
1.153 pgp_tpk_free(signer_tpk);
1.154
1.155 @@ -1704,8 +1715,16 @@
1.156 {
1.157 PEP_STATUS status = PEP_STATUS_OK;
1.158 pgp_error_t err = NULL;
1.159 - int keys_count = 0;
1.160 - pgp_tpk_t *keys = NULL;
1.161 +
1.162 + int recipient_tpk_count = 0;
1.163 + pgp_tpk_t *recipient_tpks = NULL;
1.164 +
1.165 + int recipient_count = 0;
1.166 + int recipient_alloc = 0;
1.167 + pgp_recipient_t *recipients = NULL;
1.168 + int recipient_keys_count = 0;
1.169 + pgp_key_t *recipient_keys = NULL;
1.170 +
1.171 pgp_tpk_t signer_tpk = NULL;
1.172 pgp_writer_stack_t ws = NULL;
1.173 pgp_tpk_key_iter_t iter = NULL;
1.174 @@ -1722,18 +1741,82 @@
1.175 *ctext = NULL;
1.176 *csize = 0;
1.177
1.178 - keys = calloc(stringlist_length(keylist), sizeof(*keys));
1.179 - if (keys == NULL)
1.180 + int keylist_len = stringlist_length(keylist);
1.181 +
1.182 + // We don't need to worry about extending recipient_tpks, because
1.183 + // there will be at most KEYLIST_LEN tpks, which we allocate up
1.184 + // front.
1.185 + recipient_tpks = calloc(keylist_len, sizeof(*recipient_tpks));
1.186 + if (recipient_tpks == NULL)
1.187 ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.188
1.189 + // Because there may be multiple encryption keys per TPK, we may
1.190 + // need to extend recipient_keys and recipients.
1.191 + recipient_alloc = keylist_len;
1.192 + recipient_keys = calloc(recipient_alloc, sizeof(*recipient_keys));
1.193 + if (recipient_keys == NULL)
1.194 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.195 +
1.196 + recipients = calloc(recipient_alloc, sizeof(*recipients));
1.197 + if (recipients == NULL)
1.198 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.199 +
1.200 +
1.201 // Get the keys for the recipients.
1.202 const stringlist_t *_keylist;
1.203 for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
1.204 assert(_keylist->value);
1.205 - pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(_keylist->value);
1.206 - status = tpk_find_by_fpr(session, pgp_fpr, false, &keys[keys_count ++], NULL);
1.207 - pgp_fingerprint_free(pgp_fpr);
1.208 - ERROR_OUT(NULL, status, "Looking up key for recipient '%s'", _keylist->value);
1.209 +
1.210 + pgp_tpk_t tpk;
1.211 + status = tpk_find_by_fpr_hex(session, _keylist->value,
1.212 + false, &tpk, NULL);
1.213 + // We couldn't find a key for this recipient.
1.214 + ERROR_OUT(NULL, status,
1.215 + "Looking up key for recipient '%s'", _keylist->value);
1.216 +
1.217 + recipient_tpks[recipient_tpk_count ++] = tpk;
1.218 +
1.219 + // Collect all of the keys that have the encryption for
1.220 + // transport capability.
1.221 + pgp_tpk_key_iter_t iter = pgp_tpk_key_iter_valid(tpk);
1.222 + if (! iter)
1.223 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.224 + pgp_tpk_key_iter_encrypting_capable_for_transport(iter);
1.225 +
1.226 + pgp_key_t key;
1.227 + while ((key = pgp_tpk_key_iter_next (iter, NULL, NULL))) {
1.228 + assert(recipient_count == recipient_keys_count);
1.229 + if (recipient_count == recipient_alloc) {
1.230 + assert(recipient_alloc > 0);
1.231 + recipient_alloc *= 2;
1.232 +
1.233 + void *t = reallocarray(recipient_keys, recipient_alloc,
1.234 + sizeof(*recipient_keys));
1.235 + if (! t)
1.236 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.237 + recipient_keys = t;
1.238 +
1.239 + t = reallocarray(recipients, recipient_alloc,
1.240 + sizeof(*recipients));
1.241 + if (! t)
1.242 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.243 + recipients = t;
1.244 + }
1.245 +
1.246 + // pgp_recipient_new consumes the passed key id, but it
1.247 + // only references key (i.e., we still have to free key).
1.248 + pgp_keyid_t keyid = pgp_key_keyid(key);
1.249 + if (! key)
1.250 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.251 +
1.252 + key = pgp_key_clone(key);
1.253 + if (! key)
1.254 + ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
1.255 + recipient_keys[recipient_keys_count++] = key;
1.256 +
1.257 + recipients[recipient_count++] = pgp_recipient_new(keyid, key);
1.258 + }
1.259 + pgp_tpk_key_iter_free(iter);
1.260 }
1.261
1.262 if (sign) {
1.263 @@ -1750,11 +1833,14 @@
1.264
1.265 ws = pgp_writer_stack_message(writer);
1.266 ws = pgp_encryptor_new (&err, ws,
1.267 - NULL, 0, keys, keys_count,
1.268 - PGP_ENCRYPTION_MODE_FOR_TRANSPORT, 0);
1.269 + NULL, 0, recipients, recipient_count,
1.270 + 0, 0);
1.271 if (!ws)
1.272 ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up encryptor");
1.273
1.274 + // pgp_encrypt_new consumes the recipients (but not the keys).
1.275 + recipient_count = 0;
1.276 +
1.277 if (sign) {
1.278 iter = pgp_tpk_key_iter_valid(signer_tpk);
1.279 pgp_tpk_key_iter_signing_capable (iter);
1.280 @@ -1778,6 +1864,8 @@
1.281 ws = pgp_signer_new(&err, ws, &signer, 1, 0);
1.282 if (!ws)
1.283 ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
1.284 + // pgp_signer_new consumes signer.
1.285 + signer = NULL;
1.286 }
1.287
1.288 ws = pgp_literal_writer_new (&err, ws);
1.289 @@ -1809,13 +1897,23 @@
1.290
1.291 out:
1.292 pgp_signer_free (signer);
1.293 - pgp_key_pair_free (signing_keypair);
1.294 + // XXX: pgp_key_pair_as_signer is only supposed to reference
1.295 + // signing_keypair, but it consumes it. If this is fixed, this
1.296 + // will become a leak.
1.297 + //
1.298 + // pgp_key_pair_free (signing_keypair);
1.299 pgp_tpk_key_iter_free (iter);
1.300 pgp_tpk_free(signer_tpk);
1.301
1.302 - for (int i = 0; i < keys_count; i ++)
1.303 - pgp_tpk_free(keys[i]);
1.304 - free(keys);
1.305 + for (int i = 0; i < recipient_count; i ++)
1.306 + pgp_recipient_free(recipients[i]);
1.307 + free(recipients);
1.308 + for (int i = 0; i < recipient_keys_count; i ++)
1.309 + pgp_key_free(recipient_keys[i]);
1.310 + free(recipient_keys);
1.311 + for (int i = 0; i < recipient_tpk_count; i ++)
1.312 + pgp_tpk_free(recipient_tpks[i]);
1.313 + free(recipient_tpks);
1.314
1.315 T("-> %s", pEp_status_to_string(status));
1.316 return status;
1.317 @@ -2267,7 +2365,7 @@
1.318 bool revoked = false;
1.319 // Don't add revoked keys to the keyinfo_list.
1.320 if (keyinfo_list) {
1.321 - pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
1.322 + pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
1.323 pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
1.324 pgp_revocation_status_free(rs);
1.325 if (rsv == PGP_REVOCATION_STATUS_REVOKED)
1.326 @@ -2469,7 +2567,7 @@
1.327 status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
1.328 ERROR_OUT(NULL, status, "Looking up '%s'", fpr);
1.329
1.330 - uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary(tpk));
1.331 + uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary_key(tpk));
1.332 if (creation_time > t)
1.333 // The creation time is after the expiration time!
1.334 ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
1.335 @@ -2507,6 +2605,10 @@
1.336
1.337 out:
1.338 pgp_signer_free (signer);
1.339 + // XXX: pgp_key_pair_as_signer is only supposed to reference
1.340 + // signing_keypair, but it consumes it. If this is fixed, this
1.341 + // will become a leak.
1.342 + //
1.343 pgp_key_pair_free (keypair);
1.344 pgp_tpk_key_iter_free (iter);
1.345 pgp_tpk_free(tpk);
1.346 @@ -2555,7 +2657,7 @@
1.347 if (! tpk)
1.348 ERROR_OUT(err, PEP_UNKNOWN_ERROR, "setting expiration");
1.349
1.350 - assert(pgp_revocation_status_variant(pgp_tpk_revocation_status(tpk))
1.351 + assert(pgp_revocation_status_variant(pgp_tpk_revoked(tpk, 0))
1.352 == PGP_REVOCATION_STATUS_REVOKED);
1.353
1.354 status = tpk_save(session, tpk, NULL);
1.355 @@ -2575,7 +2677,7 @@
1.356 static void _pgp_key_expired(pgp_tpk_t tpk, const time_t when, bool* expired)
1.357 {
1.358 // Is the TPK live?
1.359 - *expired = !pgp_tpk_alive_at(tpk, when);
1.360 + *expired = !pgp_tpk_alive(tpk, when);
1.361
1.362 #ifdef TRACING
1.363 {
1.364 @@ -2633,7 +2735,7 @@
1.365
1.366 out:
1.367 // Er, this might be problematic in terms of internal vs. external in log. FIXME?
1.368 - T("(%s) -> %s (expired: %d)", fpr, pEp_status_to_string(status), *expired);
1.369 + T(" -> expired: %d", *expired);
1.370 return;
1.371 }
1.372
1.373 @@ -2680,7 +2782,7 @@
1.374 pgp_fingerprint_free(pgp_fpr);
1.375 ERROR_OUT(NULL, status, "Looking up %s", fpr);
1.376
1.377 - pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
1.378 + pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
1.379 *revoked = pgp_revocation_status_variant(rs) == PGP_REVOCATION_STATUS_REVOKED;
1.380 pgp_revocation_status_free (rs);
1.381 pgp_tpk_free(tpk);
1.382 @@ -2724,7 +2826,7 @@
1.383 // goto out;
1.384 // }
1.385
1.386 - pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
1.387 + pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
1.388 pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
1.389 pgp_revocation_status_free(rs);
1.390 if (rsv == PGP_REVOCATION_STATUS_REVOKED) {
1.391 @@ -2798,7 +2900,7 @@
1.392 pgp_fingerprint_free(pgp_fpr);
1.393 ERROR_OUT(NULL, status, "Looking up %s", fpr);
1.394
1.395 - pgp_key_t k = pgp_tpk_primary(tpk);
1.396 + pgp_key_t k = pgp_tpk_primary_key(tpk);
1.397 *created = pgp_key_creation_time(k);
1.398 pgp_tpk_free(tpk);
1.399
2.1 --- a/test/README.md Wed Nov 20 16:11:25 2019 +0100
2.2 +++ b/test/README.md Mon Nov 25 11:00:36 2019 +0100
2.3 @@ -41,27 +41,29 @@
2.4
2.5 ##### Debian and Ubuntu (and derivatives)
2.6
2.7 -Thanks to Erik Smistad for this starting point (condensed from [Getting Started
2.8 -with Google Test On
2.9 -Ubuntu](https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/)):
2.10 +Using the libgtest-dev is easy, but not straightforward.
2.11 +Unfortunately, the version of google test in Debian Buster is too old:
2.12 +it's version 1.8 and we require version 1.9. Version 1.9 is available
2.13 +in Debian Testing, but it is built with g++ 9.0, which is ABI
2.14 +incompatible with binaries built with g++ 8.0, which is in Debian
2.15 +stable. Specifically, gcc has changed the semantics of std::string
2.16 +with C++11 and using g++ 8.0 results in the errors like the following:
2.17
2.18 - 1. Install the packages `cmake` and `libgtest-dev` from the repository. This
2.19 - will install the gtest source files to `/usr/src/gtest`. You'll still need to
2.20 - compile the code and link the library files to be able to use them.
2.21 + undefined reference to `std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream()'
2.22
2.23 - 2. Compile the source files:
2.24 - ```
2.25 - cd /usr/src/gtest
2.26 - sudo cmake CMakeLists.txt
2.27 - sudo make
2.28 - ```
2.29 +It's possible to install g++ 9.0 from testing to get the test suite
2.30 +working, but that breaks other things (at least for me -Neal).
2.31 +Instead, the easiest thing to do it to rebuild gtest for Debian
2.32 +Stable. This is straightforward:
2.33
2.34 - 3. Copy/symlink the libraries to the library location of your choice (here,
2.35 - it's `/usr/lib`, hence the `sudo`, but as long as it's in your library path,
2.36 - it shouldn't matter where you stick it):
2.37 - ```
2.38 - sudo cp *.a /usr/lib
2.39 - ```
2.40 + $ sudo apt install build-essential cmake debhelper
2.41 + $ apt source -t testing libgtest-dev
2.42 + $ cd googletest-1.9.0.20190831
2.43 + $ dpkg-buildpackage -us -uc
2.44 + ...
2.45 + $ sudo dpkg -i googletest_1.9.0.20190831-1_amd64.deb libgtest-dev_1.9.0.20190831-1_amd64.deb
2.46 +
2.47 +That's it.
2.48
2.49 ##### MacOS
2.50
2.51 @@ -197,6 +199,9 @@
2.52 gdb --args ./EngineTests --gtest_filter=TestSuiteName.test_function_name
2.53 ```
2.54
2.55 +When debugging a failing test, use '--gtest_break_on_failure' to have
2.56 +gtest automatically break into the debugger where the assertion fails.
2.57 +
2.58 # Creating new tests
2.59
2.60 Script next on the agenda...
3.1 --- a/test/src/test_util.cc Wed Nov 20 16:11:25 2019 +0100
3.2 +++ b/test/src/test_util.cc Mon Nov 25 11:00:36 2019 +0100
3.3 @@ -13,6 +13,7 @@
3.4 #include <sstream>
3.5 #include <iostream>
3.6 #include <stdexcept>
3.7 +#include <algorithm>
3.8 #include <stdlib.h>
3.9 #include <sys/stat.h>
3.10 #include <errno.h>