add support for client authentication via certificates
The SASL EXTERNAL method is implemented to make this possible. Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This commit is contained in:
committed by
Dmitry Podgorny
parent
cf2f7147d9
commit
18c95fa7bd
46
src/auth.c
46
src/auth.c
@@ -242,6 +242,9 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
|||||||
|
|
||||||
if (strcasecmp(text, "PLAIN") == 0)
|
if (strcasecmp(text, "PLAIN") == 0)
|
||||||
conn->sasl_support |= SASL_MASK_PLAIN;
|
conn->sasl_support |= SASL_MASK_PLAIN;
|
||||||
|
else if (strcasecmp(text, "EXTERNAL") == 0 &&
|
||||||
|
conn->tls_client_cert)
|
||||||
|
conn->sasl_support |= SASL_MASK_EXTERNAL;
|
||||||
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
||||||
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
||||||
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
|
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
|
||||||
@@ -651,6 +654,49 @@ static void _auth(xmpp_conn_t *conn)
|
|||||||
|
|
||||||
/* SASL ANONYMOUS was tried, unset flag */
|
/* SASL ANONYMOUS was tried, unset flag */
|
||||||
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
|
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
|
||||||
|
} else if (conn->sasl_support & SASL_MASK_EXTERNAL) {
|
||||||
|
/* more crap here */
|
||||||
|
auth = _make_sasl_auth(conn, "EXTERNAL");
|
||||||
|
if (!auth) {
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
authdata = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (!authdata) {
|
||||||
|
xmpp_stanza_release(auth);
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = tls_id_on_xmppaddr(conn, 0);
|
||||||
|
if (!str || (tls_id_on_xmppaddr_num(conn) == 1 &&
|
||||||
|
strcmp(str, conn->jid) == 0)) {
|
||||||
|
xmpp_stanza_set_text(authdata, "=");
|
||||||
|
} else {
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
str = xmpp_base64_encode(conn->ctx, (void *)conn->jid,
|
||||||
|
strlen(conn->jid));
|
||||||
|
if (!str) {
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
xmpp_stanza_release(auth);
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xmpp_stanza_set_text(authdata, str);
|
||||||
|
}
|
||||||
|
xmpp_free(conn->ctx, str);
|
||||||
|
|
||||||
|
xmpp_stanza_add_child(auth, authdata);
|
||||||
|
xmpp_stanza_release(authdata);
|
||||||
|
|
||||||
|
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
|
||||||
|
"EXTERNAL");
|
||||||
|
|
||||||
|
xmpp_send(conn, auth);
|
||||||
|
xmpp_stanza_release(auth);
|
||||||
|
|
||||||
|
/* SASL EXTERNAL was tried, unset flag */
|
||||||
|
conn->sasl_support &= ~SASL_MASK_EXTERNAL;
|
||||||
} else if (anonjid) {
|
} else if (anonjid) {
|
||||||
xmpp_error(conn->ctx, "auth",
|
xmpp_error(conn->ctx, "auth",
|
||||||
"No node in JID, and SASL ANONYMOUS unsupported.");
|
"No node in JID, and SASL ANONYMOUS unsupported.");
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ struct _xmpp_send_queue_t {
|
|||||||
#define SASL_MASK_SCRAMSHA1 (1 << 3)
|
#define SASL_MASK_SCRAMSHA1 (1 << 3)
|
||||||
#define SASL_MASK_SCRAMSHA256 (1 << 4)
|
#define SASL_MASK_SCRAMSHA256 (1 << 4)
|
||||||
#define SASL_MASK_SCRAMSHA512 (1 << 5)
|
#define SASL_MASK_SCRAMSHA512 (1 << 5)
|
||||||
|
#define SASL_MASK_EXTERNAL (1 << 6)
|
||||||
|
|
||||||
#define SASL_MASK_SCRAM \
|
#define SASL_MASK_SCRAM \
|
||||||
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
|
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
|
||||||
@@ -164,6 +165,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_client_cert;
|
||||||
|
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 */
|
||||||
int sasl_support; /* if true, field is a bitfield of supported
|
int sasl_support; /* if true, field is a bitfield of supported
|
||||||
mechanisms */
|
mechanisms */
|
||||||
|
|||||||
72
src/conn.c
72
src/conn.c
@@ -143,6 +143,8 @@ 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_client_cert = 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;
|
||||||
@@ -338,6 +340,10 @@ int xmpp_conn_release(xmpp_conn_t *conn)
|
|||||||
xmpp_free(ctx, conn->pass);
|
xmpp_free(ctx, conn->pass);
|
||||||
if (conn->lang)
|
if (conn->lang)
|
||||||
xmpp_free(ctx, conn->lang);
|
xmpp_free(ctx, conn->lang);
|
||||||
|
if (conn->tls_client_cert)
|
||||||
|
xmpp_free(ctx, conn->tls_client_cert);
|
||||||
|
if (conn->tls_client_key)
|
||||||
|
xmpp_free(ctx, conn->tls_client_key);
|
||||||
xmpp_free(ctx, conn);
|
xmpp_free(ctx, conn);
|
||||||
released = 1;
|
released = 1;
|
||||||
}
|
}
|
||||||
@@ -394,6 +400,58 @@ 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 Client Certificate and Private Key that will be bound to the
|
||||||
|
* 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
|
||||||
|
* make a copy of the strings passed in.
|
||||||
|
* Currently only non-encrypted Private Keys are supported.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param cert path to a certificate file
|
||||||
|
* @param key path to a private key file
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
|
||||||
|
const char *const cert,
|
||||||
|
const char *const key)
|
||||||
|
{
|
||||||
|
xmpp_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
|
||||||
|
if (conn->tls_client_cert)
|
||||||
|
xmpp_free(conn->ctx, conn->tls_client_cert);
|
||||||
|
conn->tls_client_cert = xmpp_strdup(conn->ctx, cert);
|
||||||
|
if (conn->tls_client_key)
|
||||||
|
xmpp_free(conn->ctx, conn->tls_client_key);
|
||||||
|
conn->tls_client_key = xmpp_strdup(conn->ctx, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the number of xmppAddr entries in the client certificate.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
*
|
||||||
|
* @return the number of xmppAddr entries in the client certificate
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
|
||||||
|
{
|
||||||
|
return tls_id_on_xmppaddr_num(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a specific xmppAddr entry.
|
||||||
|
*
|
||||||
|
* @param conn a Strophe connection object
|
||||||
|
* @param n the index of the entry, starting at 0
|
||||||
|
*
|
||||||
|
* @return a string containing the xmppAddr or NULL if n is out of range
|
||||||
|
*
|
||||||
|
* @ingroup Connections
|
||||||
|
*/
|
||||||
|
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *const conn, unsigned int n)
|
||||||
|
{
|
||||||
|
return tls_id_on_xmppaddr(conn, n);
|
||||||
|
}
|
||||||
|
|
||||||
/** Get the password used for authentication of a connection.
|
/** Get the password used for authentication of a connection.
|
||||||
*
|
*
|
||||||
* @param conn a Strophe connection object
|
* @param conn a Strophe connection object
|
||||||
@@ -470,6 +528,20 @@ int xmpp_connect_client(xmpp_conn_t *conn,
|
|||||||
int found = XMPP_DOMAIN_NOT_FOUND;
|
int found = XMPP_DOMAIN_NOT_FOUND;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (!conn->jid && conn->tls_client_cert) {
|
||||||
|
if (tls_id_on_xmppaddr_num(conn) != 1) {
|
||||||
|
xmpp_debug(conn->ctx, "xmpp",
|
||||||
|
"Client certificate contains multiple or no xmppAddr "
|
||||||
|
"and no JID was given to be used.");
|
||||||
|
return XMPP_EINVOP;
|
||||||
|
}
|
||||||
|
conn->jid = tls_id_on_xmppaddr(conn, 0);
|
||||||
|
if (!conn->jid)
|
||||||
|
return XMPP_EMEM;
|
||||||
|
xmpp_debug(conn->ctx, "xmpp", "Use jid %s from id-on-xmppAddr.",
|
||||||
|
conn->jid);
|
||||||
|
}
|
||||||
|
|
||||||
domain = xmpp_jid_domain(conn->ctx, conn->jid);
|
domain = xmpp_jid_domain(conn->ctx, conn->jid);
|
||||||
if (!domain)
|
if (!domain)
|
||||||
return XMPP_EMEM;
|
return XMPP_EMEM;
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ void tls_shutdown(void);
|
|||||||
tls_t *tls_new(xmpp_conn_t *conn);
|
tls_t *tls_new(xmpp_conn_t *conn);
|
||||||
void tls_free(tls_t *tls);
|
void tls_free(tls_t *tls);
|
||||||
|
|
||||||
|
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
||||||
|
unsigned int tls_id_on_xmppaddr_num(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);
|
||||||
|
|||||||
@@ -47,11 +47,19 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
|
||||||
|
{
|
||||||
|
return ASN1_STRING_data(asn1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _tls {
|
struct _tls {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
SSL_CTX *ssl_ctx;
|
SSL_CTX *ssl_ctx;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
X509 *client_cert;
|
||||||
int lasterror;
|
int lasterror;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,6 +74,10 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size);
|
|||||||
static void _tls_set_error(tls_t *tls, int error);
|
static void _tls_set_error(tls_t *tls, int error);
|
||||||
static void _tls_log_error(xmpp_ctx_t *ctx);
|
static void _tls_log_error(xmpp_ctx_t *ctx);
|
||||||
static void _tls_dump_cert_info(tls_t *tls);
|
static void _tls_dump_cert_info(tls_t *tls);
|
||||||
|
static X509 *_tls_cert_read(xmpp_conn_t *conn);
|
||||||
|
static int _tls_xaddr_nid(void);
|
||||||
|
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res);
|
||||||
|
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn);
|
||||||
|
|
||||||
#define TLS_ERROR_STR(error, table) \
|
#define TLS_ERROR_STR(error, table) \
|
||||||
_tls_error_str(error, table, ARRAY_SIZE(table))
|
_tls_error_str(error, table, ARRAY_SIZE(table))
|
||||||
@@ -189,6 +201,8 @@ void tls_initialize(void)
|
|||||||
#else
|
#else
|
||||||
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
/* init xmppAddr OID */
|
||||||
|
_tls_xaddr_nid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tls_shutdown(void)
|
void tls_shutdown(void)
|
||||||
@@ -199,6 +213,7 @@ void tls_shutdown(void)
|
|||||||
* memory rather than cause random crashes of the main program.
|
* memory rather than cause random crashes of the main program.
|
||||||
*/
|
*/
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
OBJ_cleanup();
|
||||||
ERR_free_strings();
|
ERR_free_strings();
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
CRYPTO_cleanup_all_ex_data();
|
CRYPTO_cleanup_all_ex_data();
|
||||||
@@ -218,6 +233,55 @@ int tls_error(tls_t *tls)
|
|||||||
return tls->lasterror;
|
return tls->lasterror;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Search through the SubjectAlternativeNames and return the next
|
||||||
|
* id-on-xmppAddr element starting from `n`.
|
||||||
|
*/
|
||||||
|
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
|
||||||
|
{
|
||||||
|
char *ret = NULL;
|
||||||
|
int i, j;
|
||||||
|
GENERAL_NAMES *names = _tls_cert_get_names(conn);
|
||||||
|
if (!names)
|
||||||
|
return NULL;
|
||||||
|
int num_names = sk_GENERAL_NAME_num(names);
|
||||||
|
for (i = j = 0; i < num_names; ++i) {
|
||||||
|
char *res;
|
||||||
|
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
|
||||||
|
if (name == NULL)
|
||||||
|
break;
|
||||||
|
if (_tls_name_to_xmppaddr(name, &res))
|
||||||
|
continue;
|
||||||
|
if (j == (int)n) {
|
||||||
|
xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
|
||||||
|
res);
|
||||||
|
ret = xmpp_strdup(conn->ctx, res);
|
||||||
|
OPENSSL_free(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
OPENSSL_free(res);
|
||||||
|
}
|
||||||
|
GENERAL_NAMES_free(names);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
unsigned int ret = 0;
|
||||||
|
GENERAL_NAMES *names = _tls_cert_get_names(conn);
|
||||||
|
if (!names)
|
||||||
|
return 0;
|
||||||
|
int j, num_names = sk_GENERAL_NAME_num(names);
|
||||||
|
for (j = 0; j < num_names; ++j) {
|
||||||
|
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
|
||||||
|
if (_tls_name_to_xmppaddr(name, NULL))
|
||||||
|
continue;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
GENERAL_NAMES_free(names);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
tls_t *tls_new(xmpp_conn_t *conn)
|
tls_t *tls_new(xmpp_conn_t *conn)
|
||||||
{
|
{
|
||||||
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
|
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
|
||||||
@@ -249,7 +313,23 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
|||||||
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
|
||||||
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
|
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
|
||||||
|
|
||||||
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
if (conn->tls_client_cert && conn->tls_client_key) {
|
||||||
|
tls->client_cert = _tls_cert_read(conn);
|
||||||
|
if (!tls->client_cert) {
|
||||||
|
xmpp_error(tls->ctx, "tls",
|
||||||
|
"could not read client certificate");
|
||||||
|
goto err_free_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX_use_certificate_file(tls->ssl_ctx, conn->tls_client_cert,
|
||||||
|
SSL_FILETYPE_PEM);
|
||||||
|
SSL_CTX_use_PrivateKey_file(tls->ssl_ctx, conn->tls_client_key,
|
||||||
|
SSL_FILETYPE_PEM);
|
||||||
|
} else {
|
||||||
|
/* If the server asks for a client certificate, don't send one. */
|
||||||
|
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||||
|
|
||||||
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
|
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
|
||||||
@@ -261,12 +341,12 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
|||||||
*/
|
*/
|
||||||
xmpp_error(tls->ctx, "tls",
|
xmpp_error(tls->ctx, "tls",
|
||||||
"SSL_CTX_set_default_verify_paths() failed");
|
"SSL_CTX_set_default_verify_paths() failed");
|
||||||
goto err_free_ctx;
|
goto err_free_cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls->ssl = SSL_new(tls->ssl_ctx);
|
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||||
if (tls->ssl == NULL)
|
if (tls->ssl == NULL)
|
||||||
goto err_free_ctx;
|
goto err_free_cert;
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT)
|
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT)
|
||||||
/* Enable SNI. */
|
/* Enable SNI. */
|
||||||
@@ -301,6 +381,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
|||||||
|
|
||||||
err_free_ssl:
|
err_free_ssl:
|
||||||
SSL_free(tls->ssl);
|
SSL_free(tls->ssl);
|
||||||
|
err_free_cert:
|
||||||
|
X509_free(tls->client_cert);
|
||||||
err_free_ctx:
|
err_free_ctx:
|
||||||
SSL_CTX_free(tls->ssl_ctx);
|
SSL_CTX_free(tls->ssl_ctx);
|
||||||
err:
|
err:
|
||||||
@@ -312,6 +394,7 @@ err:
|
|||||||
void tls_free(tls_t *tls)
|
void tls_free(tls_t *tls)
|
||||||
{
|
{
|
||||||
SSL_free(tls->ssl);
|
SSL_free(tls->ssl);
|
||||||
|
X509_free(tls->client_cert);
|
||||||
SSL_CTX_free(tls->ssl_ctx);
|
SSL_CTX_free(tls->ssl_ctx);
|
||||||
xmpp_free(tls->ctx, tls);
|
xmpp_free(tls->ctx, tls);
|
||||||
}
|
}
|
||||||
@@ -509,3 +592,89 @@ static void _tls_dump_cert_info(tls_t *tls)
|
|||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static X509 *_tls_cert_read(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
if (conn->tls && conn->tls->client_cert)
|
||||||
|
return conn->tls->client_cert;
|
||||||
|
BIO *f = BIO_new_file(conn->tls_client_cert, "r");
|
||||||
|
if (!f) {
|
||||||
|
xmpp_debug(conn->ctx, "tls", "f == NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
X509 *c = PEM_read_bio_X509(f, NULL, NULL, NULL);
|
||||||
|
BIO_free(f);
|
||||||
|
if (!c) {
|
||||||
|
unsigned long error;
|
||||||
|
while ((error = ERR_get_error()) != 0) {
|
||||||
|
xmpp_debug(conn->ctx, "tls", "c == NULL: %s",
|
||||||
|
ERR_error_string(error, NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tls_xaddr_nid(void)
|
||||||
|
{
|
||||||
|
static int xaddr_nid = NID_undef;
|
||||||
|
if (xaddr_nid == NID_undef) {
|
||||||
|
xaddr_nid = OBJ_create("1.3.6.1.5.5.7.8.5", "id-on-xmppAddr",
|
||||||
|
"XmppAddr Identifier");
|
||||||
|
}
|
||||||
|
return xaddr_nid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn)
|
||||||
|
{
|
||||||
|
X509 *client_cert;
|
||||||
|
GENERAL_NAMES *names = NULL;
|
||||||
|
client_cert = _tls_cert_read(conn);
|
||||||
|
if (!client_cert)
|
||||||
|
return NULL;
|
||||||
|
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
|
||||||
|
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
|
||||||
|
if (!san_ext)
|
||||||
|
goto OUT;
|
||||||
|
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
|
||||||
|
if (!data)
|
||||||
|
goto OUT;
|
||||||
|
const unsigned char *d = ASN1_STRING_get0_data(data);
|
||||||
|
if (!d)
|
||||||
|
goto OUT;
|
||||||
|
names = d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
|
||||||
|
OUT:
|
||||||
|
if (!conn->tls || !conn->tls->client_cert)
|
||||||
|
X509_free(client_cert);
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert GENERAL_NAME* to a string
|
||||||
|
*
|
||||||
|
* This checks whether the GENERAL_NAME* that is given has the
|
||||||
|
* correct id-on-xmppAddr set and then optionally converts this
|
||||||
|
* form ASN.1 to a string/char*.
|
||||||
|
*
|
||||||
|
* When `res` pointer is set to NULL this method doesn't allocate
|
||||||
|
* the result but only checks whether it is in the correct format.
|
||||||
|
*
|
||||||
|
* @param name Pointer to the GENERAL_NAME that shall be converted
|
||||||
|
* @param res Result-pointer (optional, can be NULL)
|
||||||
|
*
|
||||||
|
* @return classic Unix style - 0=success, 1=error
|
||||||
|
*/
|
||||||
|
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res)
|
||||||
|
{
|
||||||
|
ASN1_OBJECT *oid;
|
||||||
|
ASN1_TYPE *val;
|
||||||
|
if (!name || name->type != GEN_OTHERNAME)
|
||||||
|
return 1;
|
||||||
|
if (GENERAL_NAME_get0_otherName(name, &oid, &val) == 0)
|
||||||
|
return 1;
|
||||||
|
if (OBJ_obj2nid(oid) != _tls_xaddr_nid() || !val)
|
||||||
|
return 1;
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
if (ASN1_STRING_to_UTF8((unsigned char **)res, val->value.asn1_string) < 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -234,6 +234,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_client_cert(xmpp_conn_t *conn,
|
||||||
|
const char *cert,
|
||||||
|
const char *key);
|
||||||
|
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
|
||||||
|
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
|
||||||
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
|
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
|
||||||
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
|
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
|
||||||
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
|
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
|
||||||
|
|||||||
Reference in New Issue
Block a user