diff options
author | defanor <defanor@uberspace.net> | 2021-02-07 23:24:51 +0300 |
---|---|---|
committer | defanor <defanor@uberspace.net> | 2021-02-07 23:24:51 +0300 |
commit | df73e8fe84d3c2c544d12ffa78b310544bb395bb (patch) | |
tree | 05462beb52fb96392fe4df3540dbe3047ccceba3 | |
parent | 81a85c55ef1159ac4baee59dddcd33a47099e678 (diff) |
Add dedicated functions for message signing and encryption
-rw-r--r-- | src/rexmpp_console.c | 15 | ||||
-rw-r--r-- | src/rexmpp_openpgp.c | 164 | ||||
-rw-r--r-- | src/rexmpp_openpgp.h | 8 |
3 files changed, 127 insertions, 60 deletions
diff --git a/src/rexmpp_console.c b/src/rexmpp_console.c index 7884455..a2f14a8 100644 --- a/src/rexmpp_console.c +++ b/src/rexmpp_console.c @@ -229,6 +229,8 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { "tell <jid> <message>\n" "gtell <muc jid> <message>\n" "signcrypt <jid> <message>\n" + "sign <jid> <message>\n" + "crypt <jid> <message>\n" "publish-key <fingerprint>\n" "retract-key <fingerprint>\n" "join <conference> [as] <nick>\n" @@ -286,7 +288,9 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { rexmpp_send(s, msg); } - if (! strcmp(word, "signcrypt")) { + if ((strcmp(word, "signcrypt") == 0) || + (strcmp(word, "sign") == 0) || + (strcmp(word, "crypt") == 0)) { jid_str = strtok_r(NULL, " ", &words_save_ptr); if (jid_str == NULL || rexmpp_jid_parse(jid_str, &jid)) { return; @@ -298,7 +302,14 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { const char *rcpt[2]; rcpt[0] = jid.full; rcpt[1] = NULL; - char *b64 = rexmpp_openpgp_encrypt_sign(s, body, rcpt); + char *b64 = NULL; + if (strcmp(word, "signcrypt") == 0) { + b64 = rexmpp_openpgp_encrypt_sign(s, body, rcpt); + } else if (strcmp(word, "sign") == 0) { + b64 = rexmpp_openpgp_sign(s, body, rcpt); + } else if (strcmp(word, "crypt") == 0) { + b64 = rexmpp_openpgp_encrypt(s, body, rcpt); + } xmlNodePtr openpgp = xmlNewNode(NULL, "openpgp"); openpgp->ns = xmlNewNs(openpgp, "urn:xmpp:openpgp:0", NULL); xmlNodeAddContent(openpgp, b64); diff --git a/src/rexmpp_openpgp.c b/src/rexmpp_openpgp.c index d4a1332..a8acebb 100644 --- a/src/rexmpp_openpgp.c +++ b/src/rexmpp_openpgp.c @@ -27,8 +27,6 @@ Intentionally omitted functionality: Possible future improvements: -- Allow just signing or just encryption, not only both at once. - - A setting to generate the keys if they are missing, upload them automatically, encrypt messages opportunistically (as the XEP suggests). @@ -614,7 +612,9 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s, gpgme_data_new(&plain_dh); err = gpgme_op_decrypt_verify (s->pgp_ctx, cipher_dh, plain_dh); gpgme_data_release(cipher_dh); - if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { + + if (! (gpg_err_code(err) == GPG_ERR_NO_ERROR || + gpg_err_code(err) == GPG_ERR_NO_DATA)) { rexmpp_log(s, LOG_ERR, "Failed to decrypt/verify: %s", gpgme_strerror(err)); gpgme_data_release(plain_dh); return NULL; @@ -698,54 +698,44 @@ void rexmpp_openpgp_set_signers (rexmpp_t *s) { } } -char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, - xmlNodePtr payload, - const char **recipients) +char *rexmpp_openpgp_payload (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients, + int sign, + int crypt) { gpgme_error_t err; int sasl_err; + int i, nkeys = 0, allocated = 0; + gpgme_key_t *keys = NULL; - /* A random-length random-content padding. */ - char *rand_str, rand[256]; - gsasl_nonce(rand, 1); - size_t rand_str_len = 0, rand_len = (unsigned char)rand[0] % (255 - 16) + 16; - sasl_err = gsasl_nonce(rand, rand_len); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Random generation failure: %s", - gsasl_strerror(sasl_err)); + if (! (sign || crypt)) { + rexmpp_log(s, LOG_ERR, "Attempted to neither sign nor encrypt"); return NULL; } - sasl_err = gsasl_base64_to(rand, rand_len, &rand_str, &rand_str_len); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Base-64 encoding failure: %s", - gsasl_strerror(sasl_err)); - return NULL; - } - - /* Locate keys. */ - int i, nkeys = 0, allocated = 8; - gpgme_key_t *keys = malloc(sizeof(gpgme_key_t *) * allocated); - keys[0] = NULL; - /* Add own keys for encryption and signing. */ - rexmpp_openpgp_add_keys(s, s->initial_jid.bare, &keys, &nkeys, &allocated); - rexmpp_openpgp_set_signers(s); - - /* Add recipients' keys for encryption. */ - for (i = 0; recipients[i] != NULL; i++) { - rexmpp_openpgp_add_keys(s, recipients[i], &keys, &nkeys, &allocated); + /* Prepare an element. */ + char *elem_name = NULL; + if (sign && crypt) { + elem_name = "signcrypt"; + } else if (sign) { + elem_name = "sign"; + } else if (crypt) { + elem_name = "crypt"; } + xmlNodePtr elem = xmlNewNode(NULL, elem_name); + xmlNewNs(elem, "urn:xmpp:openpgp:0", NULL); - /* Prepare a signcrypt element. */ - xmlNodePtr signcrypt = xmlNewNode(NULL, "signcrypt"); - xmlNewNs(signcrypt, "urn:xmpp:openpgp:0", NULL); + if (sign) { + rexmpp_openpgp_set_signers(s); - /* Add all the recipients. */ - for (i = 0; recipients[i] != NULL; i++) { - xmlNodePtr to = xmlNewNode(NULL, "to"); - xmlNewNs(to, "urn:xmpp:openpgp:0", NULL); - xmlNewProp(to, "jid", recipients[i]); - xmlAddChild(signcrypt, to); + /* Add all the recipients. */ + for (i = 0; recipients[i] != NULL; i++) { + xmlNodePtr to = xmlNewNode(NULL, "to"); + xmlNewNs(to, "urn:xmpp:openpgp:0", NULL); + xmlNewProp(to, "jid", recipients[i]); + xmlAddChild(elem, to); + } } /* Add timestamp. */ @@ -754,41 +744,78 @@ char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, struct tm utc_time; gmtime_r(&t, &utc_time); strftime(time_str, 42, "%FT%TZ", &utc_time); - xmlNodePtr time = xmlNewNode(NULL, "time"); xmlNewNs(time, "urn:xmpp:openpgp:0", NULL); xmlNewProp(time, "stamp", time_str); - xmlAddChild(signcrypt, time); - - xmlNodePtr rpad = xmlNewNode(NULL, "rpad"); - xmlNewNs(rpad, "urn:xmpp:openpgp:0", NULL); - xmlNodeAddContent(rpad, rand_str); - free(rand_str); - xmlAddChild(signcrypt, rpad); + xmlAddChild(elem, time); /* Add the payload. */ xmlNodePtr pl = xmlNewNode(NULL, "payload"); xmlNewNs(pl, "urn:xmpp:openpgp:0", NULL); xmlAddChild(pl, payload); - xmlAddChild(signcrypt, pl); + xmlAddChild(elem, pl); + + if (crypt) { + /* Add keys for encryption. */ + allocated = 8; + keys = malloc(sizeof(gpgme_key_t *) * allocated); + keys[0] = NULL; + rexmpp_openpgp_add_keys(s, s->initial_jid.bare, &keys, &nkeys, &allocated); + for (i = 0; recipients[i] != NULL; i++) { + rexmpp_openpgp_add_keys(s, recipients[i], &keys, &nkeys, &allocated); + } + + /* A random-length random-content padding. */ + char *rand_str, rand[256]; + gsasl_nonce(rand, 1); + size_t rand_str_len = 0, rand_len = (unsigned char)rand[0] % (255 - 16) + 16; + sasl_err = gsasl_nonce(rand, rand_len); + if (sasl_err != GSASL_OK) { + rexmpp_log(s, LOG_ERR, "Random generation failure: %s", + gsasl_strerror(sasl_err)); + return NULL; + } + sasl_err = gsasl_base64_to(rand, rand_len, &rand_str, &rand_str_len); + if (sasl_err != GSASL_OK) { + rexmpp_log(s, LOG_ERR, "Base-64 encoding failure: %s", + gsasl_strerror(sasl_err)); + return NULL; + } + + xmlNodePtr rpad = xmlNewNode(NULL, "rpad"); + xmlNewNs(rpad, "urn:xmpp:openpgp:0", NULL); + xmlNodeAddContent(rpad, rand_str); + free(rand_str); + xmlAddChild(elem, rpad); + } /* Serialize the resulting XML. */ - char *plaintext = rexmpp_xml_serialize(signcrypt); - xmlFreeNode(signcrypt); + char *plaintext = rexmpp_xml_serialize(elem); + xmlFreeNode(elem); /* Encrypt, base64-encode. */ gpgme_data_t cipher_dh, plain_dh; gpgme_data_new(&cipher_dh); gpgme_data_new_from_mem(&plain_dh, plaintext, strlen(plaintext), 0); - err = gpgme_op_encrypt_sign(s->pgp_ctx, keys, GPGME_ENCRYPT_NO_ENCRYPT_TO, - plain_dh, cipher_dh); - for (i = 0; i < nkeys; i++) { - gpgme_key_unref(keys[i]); + if (sign && crypt) { + err = gpgme_op_encrypt_sign(s->pgp_ctx, keys, GPGME_ENCRYPT_NO_ENCRYPT_TO, + plain_dh, cipher_dh); + } else if (crypt) { + err = gpgme_op_encrypt(s->pgp_ctx, keys, GPGME_ENCRYPT_NO_ENCRYPT_TO, + plain_dh, cipher_dh); + } else if (sign) { + err = gpgme_op_sign(s->pgp_ctx, plain_dh, cipher_dh, GPGME_SIG_MODE_NORMAL); + } + if (keys != NULL) { + for (i = 0; i < nkeys; i++) { + gpgme_key_unref(keys[i]); + } + free(keys); + keys = NULL; } - free(keys); gpgme_data_release(plain_dh); if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - rexmpp_log(s, LOG_ERR, "Failed to encrypt: %s", gpgme_strerror(err)); + rexmpp_log(s, LOG_ERR, "Failed to %s: %s", elem_name, gpgme_strerror(err)); gpgme_data_release(cipher_dh); return NULL; } @@ -802,6 +829,27 @@ char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, return cipher_base64; } +char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients) +{ + return rexmpp_openpgp_payload(s, payload, recipients, 1, 1); +} + +char *rexmpp_openpgp_encrypt (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients) +{ + return rexmpp_openpgp_payload(s, payload, recipients, 0, 1); +} + +char *rexmpp_openpgp_sign (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients) +{ + return rexmpp_openpgp_payload(s, payload, recipients, 1, 0); +} + rexmpp_err_t rexmpp_openpgp_set_home_dir (rexmpp_t *s, const char *home_dir) { gpgme_engine_info_t engine_info; gpgme_error_t err; diff --git a/src/rexmpp_openpgp.h b/src/rexmpp_openpgp.h index 3785254..1db5717 100644 --- a/src/rexmpp_openpgp.h +++ b/src/rexmpp_openpgp.h @@ -31,6 +31,14 @@ char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, xmlNodePtr payload, const char **recipients); +char *rexmpp_openpgp_encrypt (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients); + +char *rexmpp_openpgp_sign (rexmpp_t *s, + xmlNodePtr payload, + const char **recipients); + /** @brief An utility function for setting GPG home directory. An appropriate time to call it is right after rexmpp_init. |