From 6146a73daaeb1df423bf5a9887e93e4302404fa5 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Sun, 24 Nov 2019 12:48:26 +0100 Subject: [PATCH] Update pgp_sequoia.c to latest sequoia version. - Use the 'pep-engine' branch. --- src/pgp_sequoia.c | 192 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 146 insertions(+), 46 deletions(-) diff --git a/src/pgp_sequoia.c b/src/pgp_sequoia.c index 50fcb6346..9a427ae4a 100644 --- a/src/pgp_sequoia.c +++ b/src/pgp_sequoia.c @@ -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; } @@ -792,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"); @@ -858,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); @@ -1240,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); @@ -1248,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 ++; @@ -1273,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; @@ -1671,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, @@ -1692,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); @@ -1706,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; @@ -1724,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) { @@ -1752,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); @@ -1780,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); @@ -1811,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; @@ -2269,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) @@ -2471,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, @@ -2509,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); @@ -2557,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); @@ -2577,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 { @@ -2635,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; } @@ -2682,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); @@ -2726,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) { @@ -2800,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);