From 163742a2d85eabfa844b08e9958a9ae348de5435 Mon Sep 17 00:00:00 2001 From: defanor Date: Sat, 2 Oct 2021 17:40:45 +0300 Subject: Use a custom base64 implementation Reducing dependency on gsasl. --- src/Makefile.am | 5 +- src/rexmpp.c | 12 ++--- src/rexmpp_base64.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/rexmpp_base64.h | 14 ++++++ src/rexmpp_jingle.c | 29 ++++++------ src/rexmpp_openpgp.c | 34 ++++++-------- 6 files changed, 175 insertions(+), 46 deletions(-) create mode 100644 src/rexmpp_base64.c create mode 100644 src/rexmpp_base64.h diff --git a/src/Makefile.am b/src/Makefile.am index b77083c..a6337ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,10 +21,11 @@ librexmpp_la_SOURCES = rexmpp_roster.h rexmpp_roster.c \ rexmpp_console.h rexmpp_console.c \ rexmpp_pubsub.h rexmpp_pubsub.c \ rexmpp_http_upload.h rexmpp_http_upload.c \ - rexmpp_jingle.h rexmpp_jingle.c + rexmpp_jingle.h rexmpp_jingle.c \ + rexmpp_base64.h rexmpp_base64.c include_HEADERS = config.h rexmpp_roster.h rexmpp_tcp.h rexmpp_socks.h rexmpp.h \ rexmpp_dns.h rexmpp_tls.h rexmpp_jid.h rexmpp_openpgp.h rexmpp_console.h \ - rexmpp_pubsub.h rexmpp_http_upload.h rexmpp_jingle.h + rexmpp_pubsub.h rexmpp_http_upload.h rexmpp_jingle.h rexmpp_base64.h librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) \ $(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \ diff --git a/src/rexmpp.c b/src/rexmpp.c index 5d45f6e..b754f49 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -39,6 +39,7 @@ #include "rexmpp_console.h" #include "rexmpp_http_upload.h" #include "rexmpp_jingle.h" +#include "rexmpp_base64.h" struct rexmpp_iq_cacher { rexmpp_iq_callback_t cb; @@ -224,7 +225,7 @@ char *rexmpp_capabilities_hash (rexmpp_t *s, char *sha1 = malloc(sha1_len); if (sha1 != NULL) { gcry_md_hash_buffer(GCRY_MD_SHA1, sha1, str, strlen(str)); - gsasl_base64_to(sha1, sha1_len, &out, &out_len); + rexmpp_base64_to(sha1, sha1_len, &out, &out_len); free(sha1); } free(str); @@ -835,16 +836,11 @@ const char *jid_bare_to_host (const char *jid_bare) { } char *rexmpp_gen_id (rexmpp_t *s) { - int sasl_err; + (void)s; char buf_raw[18], *buf_base64 = NULL; size_t buf_base64_len = 0; gcry_create_nonce(buf_raw, 18); - sasl_err = gsasl_base64_to(buf_raw, 18, &buf_base64, &buf_base64_len); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Base-64 encoding failure: %s", - gsasl_strerror(sasl_err)); - return NULL; - } + rexmpp_base64_to(buf_raw, 18, &buf_base64, &buf_base64_len); return buf_base64; } diff --git a/src/rexmpp_base64.c b/src/rexmpp_base64.c new file mode 100644 index 0000000..28afc7b --- /dev/null +++ b/src/rexmpp_base64.c @@ -0,0 +1,127 @@ +/** + @file rexmpp_base64.c + @brief Base64 implementation + @author defanor + @date 2021 + @copyright MIT license. + + Implements RFC 4648. +*/ + +#include +#include + +#include "rexmpp_base64.h" + + +char map_range (char x, char from_start, char from_end, char to_start, char otherwise) { + if (x >= from_start && x <= from_end) { + return (to_start + x - from_start); + } else { + return otherwise; + } +} + +char to_b64 (char x) { + return map_range(x, 0, 25, 'A', + map_range(x, 26, 51, 'a', + map_range(x, 52, 61, '0', + map_range(x, 62, 62, '+', + map_range(x, 63, 63, '/', + '='))))); +} + +char from_b64 (char x) { + return map_range(x, 'A', 'Z', 0, + map_range(x, 'a', 'z', 26, + map_range(x, '0', '9', 52, + map_range(x, '+', '+', 62, + map_range(x, '/', '/', 63, + 64))))); +} + + +int rexmpp_base64_to (const char *in, size_t in_len, char **out, size_t *out_len) { + if (in_len == 0) { + return -1; + } + if (in == NULL) { + return -1; + } + *out_len = (in_len + 2) / 3 * 4; + char *res = malloc(*out_len + 1); + if (res == NULL) { + return -1; + } + res[*out_len] = '\0'; + *out = res; + while (res < *out + *out_len) { + char a = in[0]; + char b = in_len > 1 ? in[1] : 0; + char c = in_len > 2 ? in[2] : 0; + res[0] = to_b64((a & 0xFC) >> 2); + res[1] = to_b64(((a & 0x03) << 4) | ((b & 0xF0) >> 4)); + res[2] = in_len > 1 ? to_b64((((b & 0x0F) << 2) | ((c & 0xC0) >> 6))) : '='; + res[3] = in_len > 2 ? to_b64((c & 0x3F)) : '='; + in_len -= 3; + in += 3; + res += 4; + } + return 0; +} + +int rexmpp_base64_from (const char *in, size_t in_len, char **out, size_t *out_len) { + if (in_len == 0) { + return -1; + } + if (in == NULL) { + return -1; + } + if (in_len % 4) { + return -1; + } + *out_len = in_len / 4 * 3; + char *res = malloc(*out_len); + if (res == NULL) { + return -1; + } + *out = res; + while (res < *out + *out_len) { + char a = from_b64(in[0]); + char b = from_b64(in[1]); + char c = in[2] == '=' ? 0 : from_b64(in[2]); + char d = in[3] == '=' ? 0 : from_b64(in[3]); + if ((a | b | c | d) & 0xC0) { + free(*out); + *out = NULL; + *out_len = 0; + return -1; + } + res[0] = (a << 2) | ((b & 0x30) >> 4); + res[1] = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); + res[2] = ((c & 0x03) << 6) | d; + + if (in[2] == '=') { + if (in[3] != '=') { + free(*out); + *out = NULL; + *out_len = 0; + return -1; + } + *out_len = *out_len - 1; + } + if (in[3] == '=') { + if (res + 3 < *out + *out_len) { + free(*out); + *out = NULL; + *out_len = 0; + return -1; + } + *out_len = *out_len - 1; + } + + in += 4; + res += 3; + } + return 0; +} diff --git a/src/rexmpp_base64.h b/src/rexmpp_base64.h new file mode 100644 index 0000000..e681ed9 --- /dev/null +++ b/src/rexmpp_base64.h @@ -0,0 +1,14 @@ +/** + @file rexmpp_base64.h + @brief Base64 implementation + @author defanor + @date 2021 + @copyright MIT license. + + Implements RFC 4648, with API similar to gsasl's. +*/ + +#include + +int rexmpp_base64_to (const char *in, size_t in_len, char **out, size_t *out_len); +int rexmpp_base64_from (const char *in, size_t in_len, char **out, size_t *out_len); diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c index 1e0674c..453ada8 100644 --- a/src/rexmpp_jingle.c +++ b/src/rexmpp_jingle.c @@ -16,11 +16,11 @@ The following XEPs are handled here so far: #include #include #include -#include #include #include "rexmpp.h" #include "rexmpp_jingle.h" +#include "rexmpp_base64.h" rexmpp_jingle_session_t * @@ -291,10 +291,10 @@ rexmpp_jingle_send_file (rexmpp_t *s, char *hash_base64 = NULL; size_t hash_base64_len = 0; - gsasl_base64_to(gcry_md_read(hd, GCRY_MD_SHA256), - gcry_md_get_algo_dlen(GCRY_MD_SHA256), - &hash_base64, - &hash_base64_len); + rexmpp_base64_to(gcry_md_read(hd, GCRY_MD_SHA256), + gcry_md_get_algo_dlen(GCRY_MD_SHA256), + &hash_base64, + &hash_base64_len); xmlNodePtr file_hash = rexmpp_xml_new_node("hash", "urn:xmpp:hashes:2"); xmlNewProp(file_hash, "algo", "sha-256"); xmlNodeAddContent(file_hash, hash_base64); @@ -303,10 +303,10 @@ rexmpp_jingle_send_file (rexmpp_t *s, hash_base64 = NULL; hash_base64_len = 0; - gsasl_base64_to(gcry_md_read(hd, GCRY_MD_SHA3_256), - gcry_md_get_algo_dlen(GCRY_MD_SHA3_256), - &hash_base64, - &hash_base64_len); + rexmpp_base64_to(gcry_md_read(hd, GCRY_MD_SHA3_256), + gcry_md_get_algo_dlen(GCRY_MD_SHA3_256), + &hash_base64, + &hash_base64_len); file_hash = rexmpp_xml_new_node("hash", "urn:xmpp:hashes:2"); xmlNewProp(file_hash, "algo", "sha3-256"); xmlNodeAddContent(file_hash, hash_base64); @@ -390,7 +390,7 @@ void rexmpp_jingle_send_cb (rexmpp_t *s, xmlNewProp(data, "sid", session->ibb_sid); char *out = NULL; size_t out_len = 0; - gsasl_base64_to(buf, len, &out, &out_len); + rexmpp_base64_to(buf, len, &out, &out_len); xmlNodeAddContent(data, out); free(out); snprintf(buf, 11, "%u", session->ibb_seq); @@ -535,12 +535,11 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) { char *data = NULL, *data_base64 = xmlNodeGetContent(ibb_data); if (data_base64 != NULL) { size_t data_len = 0; - int sasl_err = gsasl_base64_from(data_base64, strlen(data_base64), - &data, &data_len); + int base64_err = rexmpp_base64_from(data_base64, strlen(data_base64), + &data, &data_len); free(data_base64); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Base-64 decoding failure: %s", - gsasl_strerror(sasl_err)); + if (base64_err != 0) { + rexmpp_log(s, LOG_ERR, "Base-64 decoding failure"); } else { size_t written = fwrite(data, 1, data_len, session->f); if (written != data_len) { diff --git a/src/rexmpp_openpgp.c b/src/rexmpp_openpgp.c index 09b2b4e..13cee44 100644 --- a/src/rexmpp_openpgp.c +++ b/src/rexmpp_openpgp.c @@ -49,12 +49,12 @@ Possible future improvements: #endif #include #include -#include #include "rexmpp.h" #include "rexmpp_openpgp.h" #include "rexmpp_jid.h" #include "rexmpp_pubsub.h" +#include "rexmpp_base64.h" #ifdef HAVE_GPGME @@ -107,12 +107,11 @@ void rexmpp_pgp_fp_reply (rexmpp_t *s, char *key_raw = NULL; size_t key_raw_len = 0; char *key_base64 = xmlNodeGetContent(data); - int sasl_err = - gsasl_base64_from(key_base64, strlen(key_base64), &key_raw, &key_raw_len); + int base64_err = + rexmpp_base64_from(key_base64, strlen(key_base64), &key_raw, &key_raw_len); free(key_base64); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Base-64 key decoding failure: %s", - gsasl_strerror(sasl_err)); + if (base64_err != 0) { + rexmpp_log(s, LOG_ERR, "Base-64 key decoding failure"); return; } @@ -381,7 +380,7 @@ rexmpp_err_t rexmpp_openpgp_publish_key (rexmpp_t *s, const char *fp) { char *key_raw, *key_base64 = NULL; size_t key_raw_len, key_base64_len = 0; key_raw = gpgme_data_release_and_get_mem(key_dh, &key_raw_len); - gsasl_base64_to(key_raw, key_raw_len, &key_base64, &key_base64_len); + rexmpp_base64_to(key_raw, key_raw_len, &key_base64, &key_base64_len); free(key_raw); xmlNodePtr data = xmlNewNode(NULL, "data"); xmlNewNs(data, "urn:xmpp:openpgp:0", NULL); @@ -579,11 +578,10 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s, gpgme_data_t cipher_dh, plain_dh; char *cipher_raw = NULL, *plain; size_t cipher_raw_len = 0, plain_len; - int sasl_err = gsasl_base64_from(cipher_base64, strlen(cipher_base64), - &cipher_raw, &cipher_raw_len); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "Base-64 cipher decoding failure: %s", - gsasl_strerror(sasl_err)); + int base64_err = rexmpp_base64_from(cipher_base64, strlen(cipher_base64), + &cipher_raw, &cipher_raw_len); + if (base64_err != 0) { + rexmpp_log(s, LOG_ERR, "Base-64 cipher decoding failure"); return NULL; } gpgme_data_new_from_mem(&cipher_dh, cipher_raw, cipher_raw_len, 0); @@ -683,7 +681,6 @@ char *rexmpp_openpgp_payload (rexmpp_t *s, enum rexmpp_ox_mode mode) { gpgme_error_t err; - int sasl_err; int i, nkeys = 0, allocated = 0; gpgme_key_t *keys = NULL; @@ -759,12 +756,7 @@ char *rexmpp_openpgp_payload (rexmpp_t *s, gcry_create_nonce(rand, 1); size_t rand_str_len = 0, rand_len = (unsigned char)rand[0] % (255 - 16) + 16; gcry_create_nonce(rand, rand_len); - 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; - } + rexmpp_base64_to(rand, rand_len, &rand_str, &rand_str_len); xmlNodePtr rpad = xmlNewNode(NULL, "rpad"); xmlNewNs(rpad, "urn:xmpp:openpgp:0", NULL); @@ -806,8 +798,8 @@ char *rexmpp_openpgp_payload (rexmpp_t *s, char *cipher_raw = NULL, *cipher_base64 = NULL; size_t cipher_raw_len = 0, cipher_base64_len = 0; cipher_raw = gpgme_data_release_and_get_mem(cipher_dh, &cipher_raw_len); - gsasl_base64_to(cipher_raw, cipher_raw_len, - &cipher_base64, &cipher_base64_len); + rexmpp_base64_to(cipher_raw, cipher_raw_len, + &cipher_base64, &cipher_base64_len); free(cipher_raw); return cipher_base64; -- cgit v1.2.3