summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-09-28 19:19:18 +0300
committerdefanor <defanor@uberspace.net>2023-09-28 19:19:18 +0300
commita7f47e7142127f54821c018b8037841cc727c00e (patch)
treea905ddbfacd9249d94413a9b6e81ec699183b41e
parent153439d434bc914bcfaac403da84e3e9f0bf1367 (diff)
Support Nettle and OpenSSL for hashing, in addition to Libgcrypt
-rw-r--r--README2
-rw-r--r--configure.ac21
-rw-r--r--src/Makefile.am5
-rw-r--r--src/rexmpp.c13
-rw-r--r--src/rexmpp_digest.c126
-rw-r--r--src/rexmpp_digest.h44
-rw-r--r--src/rexmpp_jingle.c37
-rw-r--r--src/rexmpp_tls.c19
8 files changed, 228 insertions, 39 deletions
diff --git a/README b/README
index 3f9f1b7..eb28c13 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@ it easy to implement a decent client application using it.
Mandatory dependencies:
- libxml2, libexpat, or rxml (Rust)
-- libgcrypt
+- gcrypt, nettle, or openssl
Optional dependencies:
diff --git a/configure.ac b/configure.ac
index 8515da1..bb25c33 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,10 +38,25 @@ AM_CONDITIONAL([USE_RUST], [test "x$with_rust" == "xyes"])
LT_INIT
-# Libgcrypt
+# Cryptographic libraries, for hashing
+
+AC_ARG_WITH([gcrypt],
+ AS_HELP_STRING([--without-gcrypt], [do not use gcrypt]))
+AC_ARG_WITH([nettle],
+ AS_HELP_STRING([--without-nettle], [do not use nettle]))
+
+AS_IF([test "x$with_gcrypt" != "xno"],
+ [AM_PATH_LIBGCRYPT([],
+ [AC_DEFINE([HAVE_GCRYPT], [1], [Libgcrypt is available])])])
+
+AS_IF([test "x$with_gcrypt" == "xno" -a "x$with_nettle" != "xno"],
+ [PKG_CHECK_MODULES([NETTLE], [nettle],
+ [AC_DEFINE([HAVE_NETTLE], [1], [Libnettle is available])])])
+
+AS_IF([test "x$with_gcrypt" == "xno" -a "x$with_nettle" == "xno"],
+ [PKG_CHECK_MODULES([OPENSSL], [openssl],
+ [AC_DEFINE([HAVE_OPENSSL], [1], [OpenSSL is available])])])
-AM_PATH_LIBGCRYPT([],
- [AC_DEFINE([HAVE_GCRYPT], [1], [Libgcrypt is available])])
# libnice (+ glib) and libsrtp for media calls, optional
diff --git a/src/Makefile.am b/src/Makefile.am
index dcf4069..d027b1b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,13 +16,14 @@ librexmpp_la_SOURCES = rexmpp_roster.h rexmpp_roster.c \
rexmpp_sasl.h rexmpp_sasl.c \
rexmpp_xml.h rexmpp_xml.c \
rexmpp_utf8.h \
- rexmpp_random.h rexmpp_random.c
+ rexmpp_random.h rexmpp_random.c \
+ rexmpp_digest.h rexmpp_digest.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_base64.h \
rexmpp_sasl.h rexmpp_xml.h rexmpp_utf8.h rexmpp_xml_parser.h \
- rexmpp_random.h
+ rexmpp_random.h rexmpp_digest.h
librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML2_CFLAGS) $(EXPAT_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 60d138f..e19386d 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -44,6 +44,7 @@
#include "rexmpp_base64.h"
#include "rexmpp_sasl.h"
#include "rexmpp_random.h"
+#include "rexmpp_digest.h"
struct rexmpp_iq_cacher {
rexmpp_iq_callback_t cb;
@@ -202,11 +203,15 @@ char *rexmpp_capabilities_hash (rexmpp_t *s,
size_t out_len = 0;
char *str = rexmpp_capabilities_string(s, info);
if (str != NULL) {
- unsigned int sha1_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
+ size_t sha1_len = rexmpp_digest_len(REXMPP_DIGEST_SHA1);
char *sha1 = malloc(sha1_len);
if (sha1 != NULL) {
- gcry_md_hash_buffer(GCRY_MD_SHA1, sha1, str, strlen(str));
- rexmpp_base64_to(sha1, sha1_len, &out, &out_len);
+ if (rexmpp_digest_buffer(REXMPP_DIGEST_SHA1,
+ str, strlen(str),
+ sha1, sha1_len) == 0)
+ {
+ rexmpp_base64_to(sha1, sha1_len, &out, &out_len);
+ }
free(sha1);
}
free(str);
@@ -606,6 +611,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
return REXMPP_E_JID;
}
+#ifdef HAVE_GCRYPT
if (! gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
rexmpp_log(s, LOG_DEBUG, "Initializing libgcrypt");
if (gcry_check_version(NULL) == NULL) {
@@ -614,6 +620,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
}
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}
+#endif
s->xml_parser = rexmpp_xml_parser_new(&sax, s);
diff --git a/src/rexmpp_digest.c b/src/rexmpp_digest.c
new file mode 100644
index 0000000..e123636
--- /dev/null
+++ b/src/rexmpp_digest.c
@@ -0,0 +1,126 @@
+/**
+ @file rexmpp_digest.c
+ @brief Cryptographic functions
+ @author defanor <defanor@uberspace.net>
+ @date 2023
+ @copyright MIT license.
+*/
+
+#include "config.h"
+#include "rexmpp_digest.h"
+
+#if defined(HAVE_GCRYPT)
+#include <gcrypt.h>
+#elif defined(HAVE_NETTLE)
+#include <nettle/nettle-meta.h>
+#include <stdlib.h>
+#elif defined(HAVE_OPENSSL)
+#include <openssl/evp.h>
+#endif
+
+size_t rexmpp_digest_len (rexmpp_digest_algorithm algo) {
+ switch (algo) {
+ case REXMPP_DIGEST_SHA1: return 20;
+ case REXMPP_DIGEST_SHA256: return 32;
+ case REXMPP_DIGEST_SHA3_256: return 32;
+ default: return 0;
+ }
+}
+
+int rexmpp_digest_buffer (rexmpp_digest_algorithm algo,
+ const void *in,
+ size_t in_len,
+ void *out,
+ size_t out_len)
+{
+ rexmpp_digest_t ctx;
+ int err = rexmpp_digest_init(&ctx, algo);
+ if (err) {
+ return err;
+ }
+ err = rexmpp_digest_update(&ctx, in, in_len);
+ if (err) {
+ return err;
+ }
+ return rexmpp_digest_finish(&ctx, out, out_len);
+}
+
+int rexmpp_digest_init (rexmpp_digest_t *ctx, rexmpp_digest_algorithm algo) {
+#if defined(HAVE_GCRYPT)
+ int gcry_algo = GCRY_MD_NONE;
+ switch (algo) {
+ case REXMPP_DIGEST_SHA1: gcry_algo = GCRY_MD_SHA1; break;
+ case REXMPP_DIGEST_SHA256: gcry_algo = GCRY_MD_SHA256; break;
+ case REXMPP_DIGEST_SHA3_256: gcry_algo = GCRY_MD_SHA3_256; break;
+ default: return -1;
+ }
+ gcry_error_t err = gcry_md_open(ctx, gcry_algo, 0);
+ if (err != GPG_ERR_NO_ERROR) {
+ return -1;
+ }
+#elif defined(HAVE_NETTLE)
+ ctx->nh = NULL;
+ switch (algo) {
+ case REXMPP_DIGEST_SHA1: ctx->nh = &nettle_sha1; break;
+ case REXMPP_DIGEST_SHA256: ctx->nh = &nettle_sha256; break;
+ case REXMPP_DIGEST_SHA3_256: ctx->nh = &nettle_sha3_256; break;
+ default: return -1;
+ }
+ ctx->nh_ctx = malloc(ctx->nh->context_size);
+ ctx->nh->init(ctx->nh_ctx);
+#elif defined(HAVE_OPENSSL)
+ const EVP_MD *md = NULL;
+ switch (algo) {
+ case REXMPP_DIGEST_SHA1: md = EVP_sha1(); break;
+ case REXMPP_DIGEST_SHA256: md = EVP_sha256(); break;
+ case REXMPP_DIGEST_SHA3_256: md = EVP_sha3_256(); break;
+ default: return -1;
+ }
+ *ctx = EVP_MD_CTX_new();
+ if (! EVP_DigestInit(*ctx, md)) {
+ EVP_MD_CTX_free(*ctx);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int rexmpp_digest_update (rexmpp_digest_t *ctx, const void *in, size_t len) {
+#if defined(HAVE_GCRYPT)
+ printf("wirte: %s %lu\n", (const char*)in, len);
+ gcry_md_write(*ctx, in, len);
+#elif defined(HAVE_NETTLE)
+ ctx->nh->update(ctx->nh_ctx, len, in);
+#elif defined(HAVE_OPENSSL)
+ if (! EVP_DigestUpdate(*ctx, in, len)) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int rexmpp_digest_finish (rexmpp_digest_t *ctx, void *out, size_t len) {
+ int ret = 0;
+#if defined(HAVE_GCRYPT)
+ if (out != NULL) {
+ unsigned char *result = gcry_md_read(*ctx, 0);
+ if (result != NULL) {
+ memcpy(out, result, len);
+ } else {
+ ret = -1;
+ }
+ }
+ gcry_md_close(*ctx);
+#elif defined(HAVE_NETTLE)
+ ctx->nh->digest(ctx->nh_ctx, len, out);
+ free(ctx->nh_ctx);
+#elif defined(HAVE_OPENSSL)
+ (void)len;
+ if (! EVP_DigestFinal_ex(*ctx, out, NULL)) {
+ ret = -1;
+ }
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+#endif
+ return ret;
+}
diff --git a/src/rexmpp_digest.h b/src/rexmpp_digest.h
new file mode 100644
index 0000000..77f198a
--- /dev/null
+++ b/src/rexmpp_digest.h
@@ -0,0 +1,44 @@
+/**
+ @file rexmpp_digest.h
+ @brief Cryptographic functions
+ @author defanor <defanor@uberspace.net>
+ @date 2023
+ @copyright MIT license.
+*/
+
+#ifndef REXMPP_DIGEST_H
+#define REXMPP_DIGEST_H
+
+typedef enum {
+ REXMPP_DIGEST_SHA1,
+ REXMPP_DIGEST_SHA256,
+ REXMPP_DIGEST_SHA3_256
+} rexmpp_digest_algorithm;
+
+
+#if defined(HAVE_GCRYPT)
+#include <gcrypt.h>
+typedef gcry_md_hd_t rexmpp_digest_t;
+#elif defined(HAVE_NETTLE)
+#include <nettle/nettle-meta.h>
+struct rexmpp_digest {
+ const struct nettle_hash *nh;
+ void *nh_ctx;
+};
+typedef struct rexmpp_digest rexmpp_digest_t;
+#elif defined(HAVE_OPENSSL)
+#include <openssl/evp.h>
+typedef EVP_MD_CTX* rexmpp_digest_t;
+#endif
+
+size_t rexmpp_digest_len (rexmpp_digest_algorithm algo);
+int rexmpp_digest_buffer (rexmpp_digest_algorithm algo,
+ const void *in,
+ size_t in_len,
+ void *out,
+ size_t out_len);
+int rexmpp_digest_init (rexmpp_digest_t *ctx, rexmpp_digest_algorithm algo);
+int rexmpp_digest_update (rexmpp_digest_t *ctx, const void *in, size_t len);
+int rexmpp_digest_finish (rexmpp_digest_t *ctx, void *out, size_t len);
+
+#endif
diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c
index 42d0099..a147a5f 100644
--- a/src/rexmpp_jingle.c
+++ b/src/rexmpp_jingle.c
@@ -27,7 +27,6 @@ A/V calls over ICE-UDP + DTLS-SRTP:
#include <syslog.h>
#include <errno.h>
#include <libgen.h>
-#include <gcrypt.h>
#include "config.h"
@@ -51,6 +50,7 @@ A/V calls over ICE-UDP + DTLS-SRTP:
#include "rexmpp_base64.h"
#include "rexmpp_random.h"
#include "rexmpp_tls.h"
+#include "rexmpp_digest.h"
/* https://en.wikipedia.org/wiki/G.711 */
@@ -665,27 +665,24 @@ rexmpp_jingle_send_file (rexmpp_t *s,
}
char buf[4096];
- gcry_md_hd_t hd;
- gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, 0);
- if (err != GPG_ERR_NO_ERROR) {
- rexmpp_log(s, LOG_ERR, "Failed to create a MD object: %s",
- gcry_strerror(err));
+ rexmpp_digest_t sha256, sha3_256;
+ if (rexmpp_digest_init(&sha256, REXMPP_DIGEST_SHA256)) {
+ rexmpp_log(s, LOG_ERR, "Failed to initialize a SHA-256 digest object");
fclose(fh);
return REXMPP_E_OTHER;
}
- err = gcry_md_enable(hd, GCRY_MD_SHA3_256);
- if (err != GPG_ERR_NO_ERROR) {
- rexmpp_log(s, LOG_ERR, "Failed to add sha3-256 to the MD object: %s",
- gcry_strerror(err));
+ if (rexmpp_digest_init(&sha3_256, REXMPP_DIGEST_SHA3_256)) {
+ rexmpp_log(s, LOG_ERR, "Failed to initialize a SHA-3-256 digest object");
+ rexmpp_digest_finish(&sha256, NULL, 0);
fclose(fh);
return REXMPP_E_OTHER;
}
size_t len = fread(buf, 1, 4096, fh);
while (len > 0) {
- gcry_md_write(hd, buf, len);
+ rexmpp_digest_update(&sha256, buf, len);
+ rexmpp_digest_update(&sha3_256, buf, len);
len = fread(buf, 1, 4096, fh);
}
- gcry_md_final(hd);
char *sid = rexmpp_gen_id(s);
char *ibb_sid = rexmpp_gen_id(s);
@@ -718,10 +715,14 @@ rexmpp_jingle_send_file (rexmpp_t *s,
rexmpp_xml_add_text(file_name, basename(path));
rexmpp_xml_add_child(file, file_name);
+ char hash[32];
char *hash_base64 = NULL;
size_t hash_base64_len = 0;
- rexmpp_base64_to((char*)gcry_md_read(hd, GCRY_MD_SHA256),
- gcry_md_get_algo_dlen(GCRY_MD_SHA256),
+
+ rexmpp_digest_finish(&sha256, hash,
+ rexmpp_digest_len(REXMPP_DIGEST_SHA256));
+ rexmpp_base64_to(hash,
+ rexmpp_digest_len(REXMPP_DIGEST_SHA256),
&hash_base64,
&hash_base64_len);
rexmpp_xml_t *file_hash =
@@ -733,8 +734,10 @@ rexmpp_jingle_send_file (rexmpp_t *s,
hash_base64 = NULL;
hash_base64_len = 0;
- rexmpp_base64_to((char*)gcry_md_read(hd, GCRY_MD_SHA3_256),
- gcry_md_get_algo_dlen(GCRY_MD_SHA3_256),
+ rexmpp_digest_finish(&sha3_256, hash,
+ rexmpp_digest_len(REXMPP_DIGEST_SHA3_256));
+ rexmpp_base64_to(hash,
+ rexmpp_digest_len(REXMPP_DIGEST_SHA3_256),
&hash_base64,
&hash_base64_len);
file_hash = rexmpp_xml_new_elem("hash", "urn:xmpp:hashes:2");
@@ -743,8 +746,6 @@ rexmpp_jingle_send_file (rexmpp_t *s,
free(hash_base64);
rexmpp_xml_add_child(file, file_hash);
- gcry_md_close(hd);
-
long fsize = ftell(fh);
fseek(fh, 0, SEEK_SET);
snprintf(buf, 11, "%ld", fsize);
diff --git a/src/rexmpp_tls.c b/src/rexmpp_tls.c
index 3d77927..c8decc0 100644
--- a/src/rexmpp_tls.c
+++ b/src/rexmpp_tls.c
@@ -9,7 +9,6 @@
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
-#include <gcrypt.h>
#include "config.h"
@@ -26,6 +25,7 @@
#endif
#include "rexmpp.h"
+#include "rexmpp_digest.h"
#include "rexmpp_tls.h"
rexmpp_tls_t *rexmpp_jingle_component_dtls(void *p);
@@ -814,11 +814,9 @@ int rexmpp_tls_my_fp (rexmpp_t *s,
char *fp_str,
size_t *fp_size)
{
- gcry_md_hd_t hd;
- gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, 0);
- if (err != GPG_ERR_NO_ERROR) {
- rexmpp_log(s, LOG_ERR, "Failed to create an MD object: %s",
- gcry_strerror(err));
+ rexmpp_digest_t digest_ctx;
+ if (rexmpp_digest_init(&digest_ctx, REXMPP_DIGEST_SHA256)) {
+ rexmpp_log(s, LOG_ERR, "Failed to initialize a digest object");
return -1;
}
@@ -834,22 +832,19 @@ int rexmpp_tls_my_fp (rexmpp_t *s,
unsigned char *buf[4096];
size_t len = fread(buf, 1, 4096, fh);
while (len > 0) {
- gcry_md_write(hd, buf, len);
+ rexmpp_digest_update(&digest_ctx, buf, len);
len = fread(buf, 1, 4096, fh);
}
- gcry_md_final(hd);
fclose(fh);
- *fp_size = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
-
- memcpy(raw_fp, gcry_md_read(hd, GCRY_MD_SHA256), *fp_size);
+ *fp_size = rexmpp_digest_len(REXMPP_DIGEST_SHA256);
+ rexmpp_digest_finish(&digest_ctx, raw_fp, *fp_size);
size_t i;
for (i = 0; i < (*fp_size); i++) {
snprintf(fp_str + i * 3, 4, "%02X:", raw_fp[i] & 0xFF);
}
fp_str[(*fp_size) * 3 - 1] = 0;
- gcry_md_close(hd);
return 0;
}