summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2021-10-02 17:40:45 +0300
committerdefanor <defanor@uberspace.net>2021-10-02 17:40:45 +0300
commit163742a2d85eabfa844b08e9958a9ae348de5435 (patch)
treee9357ca639b453f27dc157b7c5850d9e1f06260d
parent43f40dd55fa9d20b6ff29e4eca45de88ef01a2d7 (diff)
Use a custom base64 implementation
Reducing dependency on gsasl.
-rw-r--r--src/Makefile.am5
-rw-r--r--src/rexmpp.c12
-rw-r--r--src/rexmpp_base64.c127
-rw-r--r--src/rexmpp_base64.h14
-rw-r--r--src/rexmpp_jingle.c29
-rw-r--r--src/rexmpp_openpgp.c34
6 files changed, 175 insertions, 46 deletions
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 <defanor@uberspace.net>
+ @date 2021
+ @copyright MIT license.
+
+ Implements RFC 4648.
+*/
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#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 <defanor@uberspace.net>
+ @date 2021
+ @copyright MIT license.
+
+ Implements RFC 4648, with API similar to gsasl's.
+*/
+
+#include <stddef.h>
+
+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 <syslog.h>
#include <errno.h>
#include <libgen.h>
-#include <gsasl.h>
#include <gcrypt.h>
#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 <libxml/tree.h>
#include <gcrypt.h>
-#include <gsasl.h>
#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;