mirror of
https://github.com/strophe/libstrophe.git
synced 2026-07-19 20:26:21 +00:00
add callback functionality on certificate verification failure
Based on the differences to libmesode this functionality has been added. It allows a library-user to set a callback for cases where the TLS stack can't verify a received certificate and let the end-user decide what to do. examples/basic implements an example handler of said functionality. Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This commit is contained in:
@@ -48,6 +48,7 @@ libstrophe_la_SOURCES = \
|
|||||||
src/snprintf.c \
|
src/snprintf.c \
|
||||||
src/sock.c \
|
src/sock.c \
|
||||||
src/stanza.c \
|
src/stanza.c \
|
||||||
|
src/tls.c \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
src/uuid.c
|
src/uuid.c
|
||||||
libstrophe_la_SOURCES += \
|
libstrophe_la_SOURCES += \
|
||||||
|
|||||||
@@ -19,6 +19,20 @@
|
|||||||
#define KA_TIMEOUT 60
|
#define KA_TIMEOUT 60
|
||||||
#define KA_INTERVAL 1
|
#define KA_INTERVAL 1
|
||||||
|
|
||||||
|
static void print_tlscert(const xmpp_tlscert_t *cert)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) {
|
||||||
|
printf("\t%32s: %s\n", xmpp_tlscert_get_description(n),
|
||||||
|
xmpp_tlscert_get_string(cert, n));
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL)
|
||||||
|
printf("\t%32s: %s\n", "dnsName", name);
|
||||||
|
printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert));
|
||||||
|
}
|
||||||
|
|
||||||
/* define a handler for connection events */
|
/* define a handler for connection events */
|
||||||
static void conn_handler(xmpp_conn_t *conn,
|
static void conn_handler(xmpp_conn_t *conn,
|
||||||
xmpp_conn_event_t status,
|
xmpp_conn_event_t status,
|
||||||
@@ -37,6 +51,11 @@ static void conn_handler(xmpp_conn_t *conn,
|
|||||||
secured = xmpp_conn_is_secured(conn);
|
secured = xmpp_conn_is_secured(conn);
|
||||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||||
secured ? "secured" : "NOT secured");
|
secured ? "secured" : "NOT secured");
|
||||||
|
if (secured) {
|
||||||
|
xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn);
|
||||||
|
print_tlscert(cert);
|
||||||
|
xmpp_tlscert_free(cert);
|
||||||
|
}
|
||||||
xmpp_disconnect(conn);
|
xmpp_disconnect(conn);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "DEBUG: disconnected\n");
|
fprintf(stderr, "DEBUG: disconnected\n");
|
||||||
@@ -44,6 +63,23 @@ static void conn_handler(xmpp_conn_t *conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int certfail_handler(const xmpp_tlscert_t *cert,
|
||||||
|
const char *const errormsg)
|
||||||
|
{
|
||||||
|
char read_char[16] = {0};
|
||||||
|
printf("Received certificate can't be validated!\n");
|
||||||
|
printf("Reason: %s\n", errormsg);
|
||||||
|
print_tlscert(cert);
|
||||||
|
printf("Do you agree to connect?\n[y(es)|n(o)]: ");
|
||||||
|
fflush(stdout);
|
||||||
|
if (fgets(read_char, sizeof(read_char), stdin) == NULL) {
|
||||||
|
printf("fgets() failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return read_char[0] == 'y' || read_char[0] == 'Y';
|
||||||
|
}
|
||||||
|
|
||||||
static void usage(int exit_code)
|
static void usage(int exit_code)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -52,10 +88,15 @@ static void usage(int exit_code)
|
|||||||
" --jid <jid> The JID to use to authenticate.\n"
|
" --jid <jid> The JID to use to authenticate.\n"
|
||||||
" --pass <pass> The password of the JID.\n"
|
" --pass <pass> The password of the JID.\n"
|
||||||
" --tls-cert <cert> Path to client certificate.\n"
|
" --tls-cert <cert> Path to client certificate.\n"
|
||||||
|
" --capath <path> Path to an additional CA trust store "
|
||||||
|
"(directory).\n"
|
||||||
|
" --cafile <path> Path to an additional CA trust store "
|
||||||
|
"(single file).\n"
|
||||||
" --tls-key <key> Path to private key.\n\n"
|
" --tls-key <key> Path to private key.\n\n"
|
||||||
" --disable-tls Disable TLS.\n"
|
" --disable-tls Disable TLS.\n"
|
||||||
" --mandatory-tls Deny plaintext connection.\n"
|
" --mandatory-tls Deny plaintext connection.\n"
|
||||||
" --trust-tls Trust TLS certificate.\n"
|
" --trust-tls Trust TLS certificate.\n"
|
||||||
|
" --enable-certfail Enable certfail handler.\n"
|
||||||
" --legacy-ssl Use old style SSL.\n"
|
" --legacy-ssl Use old style SSL.\n"
|
||||||
" --legacy-auth Allow legacy authentication.\n"
|
" --legacy-auth Allow legacy authentication.\n"
|
||||||
" --verbose Increase the verbosity level.\n"
|
" --verbose Increase the verbosity level.\n"
|
||||||
@@ -71,9 +112,10 @@ int main(int argc, char **argv)
|
|||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
xmpp_conn_t *conn;
|
xmpp_conn_t *conn;
|
||||||
xmpp_log_t *log;
|
xmpp_log_t *log;
|
||||||
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL;
|
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL,
|
||||||
|
*capath = NULL, *cafile = NULL;
|
||||||
long flags = 0;
|
long flags = 0;
|
||||||
int tcp_keepalive = 0, verbosity = 0;
|
int tcp_keepalive = 0, verbosity = 0, certfail = 0;
|
||||||
int i;
|
int i;
|
||||||
unsigned long port = 0;
|
unsigned long port = 0;
|
||||||
|
|
||||||
@@ -95,6 +137,8 @@ int main(int argc, char **argv)
|
|||||||
verbosity++;
|
verbosity++;
|
||||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||||
tcp_keepalive = 1;
|
tcp_keepalive = 1;
|
||||||
|
else if (strcmp(argv[i], "--enable-certfail") == 0)
|
||||||
|
certfail = 1;
|
||||||
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
||||||
jid = argv[i];
|
jid = argv[i];
|
||||||
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
||||||
@@ -103,6 +147,10 @@ int main(int argc, char **argv)
|
|||||||
cert = argv[i];
|
cert = argv[i];
|
||||||
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
|
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
|
||||||
key = argv[i];
|
key = argv[i];
|
||||||
|
else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc))
|
||||||
|
capath = argv[i];
|
||||||
|
else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc))
|
||||||
|
cafile = argv[i];
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -147,6 +195,13 @@ int main(int argc, char **argv)
|
|||||||
if (password)
|
if (password)
|
||||||
xmpp_conn_set_pass(conn, password);
|
xmpp_conn_set_pass(conn, password);
|
||||||
|
|
||||||
|
if (certfail)
|
||||||
|
xmpp_conn_set_certfail_handler(conn, certfail_handler);
|
||||||
|
if (capath)
|
||||||
|
xmpp_conn_set_capath(conn, capath);
|
||||||
|
if (cafile)
|
||||||
|
xmpp_conn_set_cafile(conn, cafile);
|
||||||
|
|
||||||
/* initiate connection */
|
/* initiate connection */
|
||||||
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {
|
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ struct _xmpp_conn_t {
|
|||||||
int tls_mandatory;
|
int tls_mandatory;
|
||||||
int tls_legacy_ssl;
|
int tls_legacy_ssl;
|
||||||
int tls_trust;
|
int tls_trust;
|
||||||
|
char *tls_cafile;
|
||||||
|
char *tls_capath;
|
||||||
char *tls_client_cert;
|
char *tls_client_cert;
|
||||||
char *tls_client_key;
|
char *tls_client_key;
|
||||||
int tls_failed; /* set when tls fails, so we don't try again */
|
int tls_failed; /* set when tls fails, so we don't try again */
|
||||||
@@ -176,6 +178,7 @@ struct _xmpp_conn_t {
|
|||||||
mechanisms */
|
mechanisms */
|
||||||
int auth_legacy_enabled;
|
int auth_legacy_enabled;
|
||||||
int secured; /* set when stream is secured with TLS */
|
int secured; /* set when stream is secured with TLS */
|
||||||
|
xmpp_certfail_handler certfail_handler;
|
||||||
|
|
||||||
/* if server returns <bind/> or <session/> we must do them */
|
/* if server returns <bind/> or <session/> we must do them */
|
||||||
int bind_required;
|
int bind_required;
|
||||||
|
|||||||
68
src/conn.c
68
src/conn.c
@@ -144,11 +144,14 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
|||||||
conn->tls_legacy_ssl = 0;
|
conn->tls_legacy_ssl = 0;
|
||||||
conn->tls_trust = 0;
|
conn->tls_trust = 0;
|
||||||
conn->tls_failed = 0;
|
conn->tls_failed = 0;
|
||||||
|
conn->tls_cafile = NULL;
|
||||||
|
conn->tls_capath = NULL;
|
||||||
conn->tls_client_cert = NULL;
|
conn->tls_client_cert = NULL;
|
||||||
conn->tls_client_key = NULL;
|
conn->tls_client_key = NULL;
|
||||||
conn->sasl_support = 0;
|
conn->sasl_support = 0;
|
||||||
conn->auth_legacy_enabled = 0;
|
conn->auth_legacy_enabled = 0;
|
||||||
conn->secured = 0;
|
conn->secured = 0;
|
||||||
|
conn->certfail_handler = NULL;
|
||||||
|
|
||||||
conn->bind_required = 0;
|
conn->bind_required = 0;
|
||||||
conn->session_required = 0;
|
conn->session_required = 0;
|
||||||
@@ -345,6 +348,10 @@ int xmpp_conn_release(xmpp_conn_t *conn)
|
|||||||
xmpp_free(ctx, conn->tls_client_cert);
|
xmpp_free(ctx, conn->tls_client_cert);
|
||||||
if (conn->tls_client_key)
|
if (conn->tls_client_key)
|
||||||
xmpp_free(ctx, conn->tls_client_key);
|
xmpp_free(ctx, conn->tls_client_key);
|
||||||
|
if (conn->tls_cafile)
|
||||||
|
xmpp_free(ctx, conn->tls_cafile);
|
||||||
|
if (conn->tls_capath)
|
||||||
|
xmpp_free(ctx, conn->tls_capath);
|
||||||
xmpp_free(ctx, conn);
|
xmpp_free(ctx, conn);
|
||||||
released = 1;
|
released = 1;
|
||||||
}
|
}
|
||||||
@@ -401,6 +408,64 @@ void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
|
|||||||
conn->jid = xmpp_strdup(conn->ctx, jid);
|
conn->jid = xmpp_strdup(conn->ctx, jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set the Handler function which will be called when the TLS stack can't
|
||||||
|
* verify the CA of the server we're trying to connect to.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param hndl certfail Handler function
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
|
||||||
|
xmpp_certfail_handler hndl)
|
||||||
|
{
|
||||||
|
conn->certfail_handler = hndl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the CAfile
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param cert path to a certificate file
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
|
||||||
|
{
|
||||||
|
conn->tls_cafile = xmpp_strdup(conn->ctx, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the CApath
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param cert path to a folder containing certificates
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
|
||||||
|
{
|
||||||
|
conn->tls_capath = xmpp_strdup(conn->ctx, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieve the peer certificate
|
||||||
|
*
|
||||||
|
* The returned Certificate object must be free'd by calling
|
||||||
|
* \ref xmpp_tlscert_free
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
*
|
||||||
|
* @return a Strophe Certificate object
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
|
||||||
|
{
|
||||||
|
return tls_peer_cert(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/** Set the Client Certificate and Private Key that will be bound to the
|
/** Set the Client Certificate and Private Key that will be bound to the
|
||||||
* connection. If any of the both was previously set, it will be discarded.
|
* connection. If any of the both was previously set, it will be discarded.
|
||||||
* This should not be used after a connection is created. The function will
|
* This should not be used after a connection is created. The function will
|
||||||
@@ -412,6 +477,7 @@ void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
|
|||||||
* @param key path to a private key file
|
* @param key path to a private key file
|
||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
*/
|
*/
|
||||||
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
|
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
|
||||||
const char *const cert,
|
const char *const cert,
|
||||||
@@ -433,6 +499,7 @@ void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
|
|||||||
* @return the number of xmppAddr entries in the client certificate
|
* @return the number of xmppAddr entries in the client certificate
|
||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
*/
|
*/
|
||||||
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
|
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
|
||||||
{
|
{
|
||||||
@@ -447,6 +514,7 @@ unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
|
|||||||
* @return a string containing the xmppAddr or NULL if n is out of range
|
* @return a string containing the xmppAddr or NULL if n is out of range
|
||||||
*
|
*
|
||||||
* @ingroup Connections
|
* @ingroup Connections
|
||||||
|
* @ingroup TLS
|
||||||
*/
|
*/
|
||||||
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *const conn, unsigned int n)
|
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *const conn, unsigned int n)
|
||||||
{
|
{
|
||||||
|
|||||||
214
src/tls.c
Normal file
214
src/tls.c
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
/* tls.c
|
||||||
|
** strophe XMPP client library -- generic TLS functions
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
|
||||||
|
**
|
||||||
|
** This software is provided AS-IS with no warranty, either express
|
||||||
|
** or implied.
|
||||||
|
**
|
||||||
|
** This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* Generic TLS functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup TLS SSL/TLS specific functionality
|
||||||
|
* These functions provide SSL/TLS specific functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "strophe.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct _dnsname_t {
|
||||||
|
char **data;
|
||||||
|
size_t cur, max;
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t tlscert_dnsnames_increment = 4;
|
||||||
|
|
||||||
|
/** Get the Strophe context which is assigned to this certificate.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
*
|
||||||
|
* @return the Strophe context object where this certificate originates from
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
|
||||||
|
{
|
||||||
|
return cert->ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the Strophe connection which is assigned to this certificate.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
*
|
||||||
|
* @return the Strophe connection object where this certificate originates from
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
|
||||||
|
{
|
||||||
|
return cert->conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the complete PEM of this certificate.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
*
|
||||||
|
* @return a string containing the PEM of this certificate
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
|
||||||
|
{
|
||||||
|
return cert->pem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the dnsName entries out of the SubjectAlternativeNames.
|
||||||
|
*
|
||||||
|
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
* @param n which dnsName entry
|
||||||
|
*
|
||||||
|
* @return a string with the n'th dnsName
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
|
||||||
|
{
|
||||||
|
if (n >= cert->dnsnames->cur)
|
||||||
|
return NULL;
|
||||||
|
return cert->dnsnames->data[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get various parts of the certificate as String.
|
||||||
|
*
|
||||||
|
* c.f. \ref xmpp_cert_element_t for details.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
* @param elmnt which part of the certificate
|
||||||
|
*
|
||||||
|
* @return a string with the part of the certificate
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
|
||||||
|
xmpp_cert_element_t elmnt)
|
||||||
|
{
|
||||||
|
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
|
||||||
|
return NULL;
|
||||||
|
return cert->elements[elmnt];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a descriptive string for each xmpp_cert_element_t.
|
||||||
|
*
|
||||||
|
* c.f. \ref xmpp_cert_element_t for details.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
* @param elmnt which element
|
||||||
|
*
|
||||||
|
* @return a string with the description
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
|
||||||
|
{
|
||||||
|
static const char *descriptions[] = {
|
||||||
|
"X.509 Version",
|
||||||
|
"SerialNumber",
|
||||||
|
"Subject",
|
||||||
|
"Issuer",
|
||||||
|
"Issued On",
|
||||||
|
"Expires On",
|
||||||
|
"Public Key Algorithm",
|
||||||
|
"Certificate Signature Algorithm",
|
||||||
|
"Fingerprint SHA-1",
|
||||||
|
"Fingerprint SHA-256",
|
||||||
|
};
|
||||||
|
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
|
||||||
|
return NULL;
|
||||||
|
return descriptions[elmnt];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocate and initialize a Strophe TLS certificate object.
|
||||||
|
*
|
||||||
|
* @param ctx a Strophe context object
|
||||||
|
*
|
||||||
|
* @return a certificate object or NULL
|
||||||
|
*/
|
||||||
|
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
xmpp_tlscert_t *tlscert = xmpp_alloc(ctx, sizeof(*tlscert));
|
||||||
|
if (!tlscert)
|
||||||
|
return NULL;
|
||||||
|
memset(tlscert, 0, sizeof(*tlscert));
|
||||||
|
|
||||||
|
tlscert->dnsnames = xmpp_alloc(ctx, sizeof(*tlscert->dnsnames));
|
||||||
|
if (!tlscert->dnsnames) {
|
||||||
|
xmpp_free(ctx, tlscert);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
|
||||||
|
|
||||||
|
tlscert->ctx = ctx;
|
||||||
|
|
||||||
|
return tlscert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free a certificate object.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
void xmpp_tlscert_free(xmpp_tlscert_t *cert)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
|
||||||
|
if (cert->elements[n])
|
||||||
|
xmpp_free(cert->ctx, cert->elements[n]);
|
||||||
|
}
|
||||||
|
if (cert->dnsnames->data) {
|
||||||
|
for (n = 0; n < cert->dnsnames->cur; ++n) {
|
||||||
|
if (cert->dnsnames->data[n])
|
||||||
|
xmpp_free(cert->ctx, cert->dnsnames->data[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmpp_free(cert->ctx, cert->dnsnames->data);
|
||||||
|
xmpp_free(cert->ctx, cert->dnsnames);
|
||||||
|
if (cert->pem)
|
||||||
|
xmpp_free(cert->ctx, cert->pem);
|
||||||
|
xmpp_free(cert->ctx, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a dnsName to the Strophe TLS certificate object.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe TLS certificate object
|
||||||
|
* @param dnsname dnsName that shall be stored
|
||||||
|
*
|
||||||
|
* @return classic Unix style - 0=success, 1=error
|
||||||
|
*/
|
||||||
|
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
|
||||||
|
{
|
||||||
|
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
|
||||||
|
char **dnsnames =
|
||||||
|
xmpp_realloc(cert->ctx, cert->dnsnames->data,
|
||||||
|
(cert->dnsnames->max + tlscert_dnsnames_increment) *
|
||||||
|
sizeof(char **));
|
||||||
|
if (!dnsnames)
|
||||||
|
return 1;
|
||||||
|
cert->dnsnames->data = dnsnames;
|
||||||
|
cert->dnsnames->max += tlscert_dnsnames_increment;
|
||||||
|
}
|
||||||
|
cert->dnsnames->data[cert->dnsnames->cur++] =
|
||||||
|
xmpp_strdup(cert->ctx, dnsname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
14
src/tls.h
14
src/tls.h
@@ -21,6 +21,16 @@
|
|||||||
|
|
||||||
typedef struct _tls tls_t;
|
typedef struct _tls tls_t;
|
||||||
|
|
||||||
|
typedef struct _dnsname_t dnsname_t;
|
||||||
|
|
||||||
|
struct _xmpp_tlscert_t {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
xmpp_conn_t *conn;
|
||||||
|
char *pem;
|
||||||
|
char *elements[XMPP_CERT_ELEMENT_MAX];
|
||||||
|
dnsname_t *dnsnames;
|
||||||
|
};
|
||||||
|
|
||||||
void tls_initialize(void);
|
void tls_initialize(void);
|
||||||
void tls_shutdown(void);
|
void tls_shutdown(void);
|
||||||
|
|
||||||
@@ -30,6 +40,7 @@ void tls_free(tls_t *tls);
|
|||||||
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
||||||
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
|
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
|
||||||
|
|
||||||
|
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
|
||||||
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
||||||
|
|
||||||
int tls_start(tls_t *tls);
|
int tls_start(tls_t *tls);
|
||||||
@@ -44,4 +55,7 @@ int tls_write(tls_t *tls, const void *buff, size_t len);
|
|||||||
int tls_clear_pending_write(tls_t *tls);
|
int tls_clear_pending_write(tls_t *tls);
|
||||||
int tls_is_recoverable(int error);
|
int tls_is_recoverable(int error);
|
||||||
|
|
||||||
|
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
||||||
|
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
||||||
|
|
||||||
#endif /* __LIBSTROPHE_TLS_H__ */
|
#endif /* __LIBSTROPHE_TLS_H__ */
|
||||||
|
|||||||
58
strophe.h
58
strophe.h
@@ -122,6 +122,8 @@ typedef struct _xmpp_log_t xmpp_log_t;
|
|||||||
/* opaque run time context containing the above hooks */
|
/* opaque run time context containing the above hooks */
|
||||||
typedef struct _xmpp_ctx_t xmpp_ctx_t;
|
typedef struct _xmpp_ctx_t xmpp_ctx_t;
|
||||||
|
|
||||||
|
typedef struct _xmpp_tlscert_t xmpp_tlscert_t;
|
||||||
|
|
||||||
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
|
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
|
||||||
void xmpp_ctx_free(xmpp_ctx_t *ctx);
|
void xmpp_ctx_free(xmpp_ctx_t *ctx);
|
||||||
|
|
||||||
@@ -215,6 +217,24 @@ typedef enum {
|
|||||||
XMPP_SE_XML_NOT_WELL_FORMED
|
XMPP_SE_XML_NOT_WELL_FORMED
|
||||||
} xmpp_error_type_t;
|
} xmpp_error_type_t;
|
||||||
|
|
||||||
|
/** Certificate Elements
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
XMPP_CERT_VERSION, /**< X.509 Version */
|
||||||
|
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
|
||||||
|
XMPP_CERT_SUBJECT, /**< Subject */
|
||||||
|
XMPP_CERT_ISSUER, /**< Issuer */
|
||||||
|
XMPP_CERT_NOTBEFORE, /**< Issued on */
|
||||||
|
XMPP_CERT_NOTAFTER, /**< Expires on */
|
||||||
|
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
|
||||||
|
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
|
||||||
|
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
|
||||||
|
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
|
||||||
|
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
|
||||||
|
} xmpp_cert_element_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xmpp_error_type_t type;
|
xmpp_error_type_t type;
|
||||||
char *text;
|
char *text;
|
||||||
@@ -227,6 +247,28 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn,
|
|||||||
xmpp_stream_error_t *stream_error,
|
xmpp_stream_error_t *stream_error,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
/** The Handler function which will be called when the TLS stack can't
|
||||||
|
* verify the authenticity of a Certificate that gets presented by
|
||||||
|
* the server we're trying to connect to.
|
||||||
|
*
|
||||||
|
* When this function is called and details of the `cert` have to be
|
||||||
|
* kept, please copy them yourself. The `cert` object will be free'd
|
||||||
|
* automatically when this function returns.
|
||||||
|
*
|
||||||
|
* NB: `errormsg` is specific per certificate on OpenSSL and the same
|
||||||
|
* for all certificates on GnuTLS.
|
||||||
|
*
|
||||||
|
* @param cert a Strophe certificate object
|
||||||
|
* @param errormsg The error that caused this.
|
||||||
|
*
|
||||||
|
* @return 0 if the connection attempt should be terminated,
|
||||||
|
* 1 if the connection should be established.
|
||||||
|
*
|
||||||
|
* @ingroup TLS
|
||||||
|
*/
|
||||||
|
typedef int (*xmpp_certfail_handler)(const xmpp_tlscert_t *cert,
|
||||||
|
const char *const errormsg);
|
||||||
|
|
||||||
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
|
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
|
||||||
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
|
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
|
||||||
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
|
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
|
||||||
@@ -237,6 +279,11 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
|
|||||||
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
|
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
|
||||||
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
|
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
|
||||||
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
|
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
|
||||||
|
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
|
||||||
|
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
|
||||||
|
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
|
||||||
|
xmpp_certfail_handler hndl);
|
||||||
|
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
|
||||||
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
|
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
|
||||||
const char *cert,
|
const char *cert,
|
||||||
const char *key);
|
const char *key);
|
||||||
@@ -437,6 +484,17 @@ void xmpp_run(xmpp_ctx_t *ctx);
|
|||||||
void xmpp_stop(xmpp_ctx_t *ctx);
|
void xmpp_stop(xmpp_ctx_t *ctx);
|
||||||
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
|
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
|
||||||
|
|
||||||
|
/* TLS certificates */
|
||||||
|
|
||||||
|
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
|
||||||
|
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
|
||||||
|
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
|
||||||
|
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
|
||||||
|
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
|
||||||
|
xmpp_cert_element_t elmnt);
|
||||||
|
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt);
|
||||||
|
void xmpp_tlscert_free(xmpp_tlscert_t *cert);
|
||||||
|
|
||||||
/* UUID */
|
/* UUID */
|
||||||
|
|
||||||
char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
|
char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user