Commit 7b637c59 authored by Jarod Neuner's avatar Jarod Neuner

TLS Subject Checking in tport

sofia-sip/tport.h:
* tport_delivered_from_subjects() returns type (su_strlst_t const *)
* Export tport_subject_search()

sofia-sip/tport_tag.h + tport_tag.c:
* Remove TPTAG_TLS_VERIFY_PEER()
  - Depreciated.  Use TPTAG_TLS_VERIFY_POLICY instead.
  - Binary Compatibility is preserved.
* Add TPTAG_TLS_VERIFY_POLICY()
  - tport can verify incoming and/or outgoing connections, using:
    1) Certificate Signatures only - or -
    2) Certificate Signatures and Certificate Subjects
* Add TPTAG_TLS_VERIFY_DEPTH()
  - Restrict certificate chain verification to a set length.
* Add TPTAG_TLS_VERIFY_DATE()
  - Disable notBefore/notAfter checking (application: embedded devices)
* Add TPTAG_TLS_VERIFY_SUBJECTS()
  - Incoming connections must present client certificates with subjects
    that match an item in this list.
  - Intended Use: Proxy Authentication
* Replaced TPTAG_TRUSTED() with TPTAG_X509_SUBJECT()
  - Commented out for future use.
  - Intended Use: SIP User Identities in Server Certificates.
* Add appropriate doxygen documentation.

tport.c
* Add tport_subject_search()
  - Subject can be a hostname, IP Address, or a URI.
  - Valid subject examples include:
      example.com
      alice@example.com
      sip:alice@example.com
      sips:alice@example.com
* tport_by_addrinfo() matches tpn_canon against the subject list
    of reusable TLS connections.

tport_tls.h:
* Add tls_init_secondary()
* Remove tls_init_slave() & tls_init_client()

tport_tls.c:
* tls_verify_cb() supports TPTAG_TLS_VERIFY_DATE()
* tls_post_connection_check() verifies certificate subjects.
* tls_init_secondary()
  - Replaces tls_init_slave(), tls_init_client(), and tls_clone().

tport_type_tls.c:
* Removed erroneous reference to tport_tls_deliver()
* Fix a memory leak caused by duplicate calls to tls_clone().
* Populate the (tport_t *)->tp_subjects field with peer certificate data for
  new secondary connections.

darcs-hash:20090115155045-2152f-aaec406d8e5dbf146949d4d3cbc9f56e201cba46.gz
parent b74f9451
......@@ -339,7 +339,11 @@ TPORT_DLL int tport_delivered_from(tport_t *tp, msg_t const *msg,
tp_name_t name[1]);
/** Return TLS Subjects provided by the source transport */
TPORT_DLL su_strlst_t *tport_delivered_from_subjects(tport_t *tp, msg_t const *msg);
TPORT_DLL su_strlst_t const *tport_delivered_from_subjects(tport_t *tp,
msg_t const *msg);
/** Check if the given subject string is found in su_strlst_t */
TPORT_DLL int tport_subject_search(char const *, su_strlst_t const *);
/** Check if transport named is already resolved */
TPORT_DLL int tport_name_is_resolved(tp_name_t const *);
......
......@@ -186,18 +186,59 @@ TPORT_DLL extern tag_typedef_t tptag_tls_version;
TPORT_DLL extern tag_typedef_t tptag_tls_version_ref;
#define TPTAG_TLS_VERSION_REF(x) tptag_tls_version_ref, tag_uint_vr(&(x))
enum tport_tls_verify_policy {
TPTLS_VERIFY_NONE = 0x0,
TPTLS_VERIFY_INCOMING = 0x1,
TPTLS_VERIFY_IN = 0x1,
TPTLS_VERIFY_OUTGOING = 0x2,
TPTLS_VERIFY_OUT = 0x2,
TPTLS_VERIFY_ALL = 0x3,
TPTLS_VERIFY_SUBJECTS_IN = 0x5, /* 0x4 | TPTLS_VERIFY_INCOMING */
TPTLS_VERIFY_SUBJECTS_OUT = 0xA, /* 0x8 | TPTLS_VERIFY_OUTGOING */
TPTLS_VERIFY_SUBJECTS_ALL = 0xF,
};
TPORT_DLL extern tag_typedef_t tptag_tls_verify_policy;
#define TPTAG_TLS_VERIFY_POLICY(x) tptag_tls_verify_policy, tag_uint_v((x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_policy_ref;
#define TPTAG_TLS_VERIFY_POLICY_REF(x) tptag_tls_verify_policy_ref, tag_uint_vr(&(x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_depth;
#define TPTAG_TLS_VERIFY_DEPTH(x) tptag_tls_verify_depth, tag_uint_v((x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_depth_ref;
#define TPTAG_TLS_VERIFY_DEPTH_REF(x) \
tptag_tls_verify_depth_ref, tag_uint_vr(&(x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_date;
#define TPTAG_TLS_VERIFY_DATE(x) tptag_tls_verify_date, tag_uint_v((x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_date_ref;
#define TPTAG_TLS_VERIFY_DATE_REF(x) \
tptag_tls_verify_date_ref, tag_uint_vr(&(x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_subjects;
#define TPTAG_TLS_VERIFY_SUBJECTS(x) tptag_tls_verify_subjects, tag_cptr_v((x))
TPORT_DLL extern tag_typedef_t tptag_tls_verify_subjects_ref;
#define TPTAG_TLS_VERIFY_SUBJECTS_REF(x) \
tptag_tls_verify_subjects_ref, tag_cptr_vr(&(x), (x))
/* TPTAG_TLS_VERIFY_PEER is depreciated - Use TPTAG_TLS_VERIFY_POLICY */
TPORT_DLL extern tag_typedef_t tptag_tls_verify_peer;
#define TPTAG_TLS_VERIFY_PEER(x) tptag_tls_verify_peer, tag_uint_v((x))
#define TPTAG_TLS_VERIFY_PEER(x) TPTAG_TLS_VERIFY_POLICY( (x) ? \
TPTLS_VERIFY_ALL : TPTLS_VERIFY_NONE)
TPORT_DLL extern tag_typedef_t tptag_tls_verify_peer_ref;
#define TPTAG_TLS_VERIFY_PEER_REF(x) tptag_tls_verify_peer_ref, tag_uint_vr(&(x))
#if 0
TPORT_DLL extern tag_typedef_t tptag_trusted;
#define TPTAG_TRUSTED(x) tptag_trusted, tag_bool_v((x))
TPORT_DLL extern tag_typedef_t tport_x509_subject;
#define TPTAG_X509_SUBJECT(x) tptag_x509_subject, tag_str_v((x))
TPORT_DLL extern tag_typedef_t tptag_trusted_ref;
#define TPTAG_TRUSTED_REF(x) tptag_trusted_ref, tag_bool_vr(&(x))
TPORT_DLL extern tag_typedef_t tptag_x509_subject_ref;
#define TPTAG_X509_SUBJECT_REF(x) tptag_x509_subject_ref, tag_str_vr(&(x))
#endif
TPORT_DLL extern tag_typedef_t tptag_debug_drop;
......
......@@ -273,7 +273,7 @@ int tport_has_tls(tport_t const *self)
/** Return true if transport certificate verified successfully */
int tport_is_verified(tport_t const *self)
{
return tport_has_tls(self) && self->tp_verified;
return tport_has_tls(self) && self->tp_is_connected && self->tp_verified;
}
/** Return true if transport is being updated. */
......@@ -1465,8 +1465,8 @@ int tport_bind_set(tport_master_t *mr,
*
* @TAGS
* TPTAG_SERVER(), TPTAG_PUBLIC(), TPTAG_IDENT(), TPTAG_HTTP_CONNECT(),
* TPTAG_CERTIFICATE(), TPTAG_TLS_VERSION(), TPTAG_TLS_VERIFY_PEER, and tags used with
* tport_set_params(), especially TPTAG_QUEUESIZE().
* TPTAG_CERTIFICATE(), TPTAG_TLS_VERSION(), TPTAG_TLS_VERIFY_POLICY, and
* tags used with tport_set_params(), especially TPTAG_QUEUESIZE().
*/
int tport_tbind(tport_t *self,
tp_name_t const *tpn,
......@@ -3045,7 +3045,7 @@ int tport_delivered_from(tport_t *tp, msg_t const *msg, tp_name_t name[1])
}
/** Return TLS Subjects provided by the source transport */
su_strlst_t *tport_delivered_from_subjects(tport_t *tp, msg_t const *msg)
su_strlst_t const *tport_delivered_from_subjects(tport_t *tp, msg_t const *msg)
{
if (tp && msg && msg == tp->tp_master->mr_delivery->d_msg) {
tport_t *tp_sec = tp->tp_master->mr_delivery->d_tport;
......@@ -3069,6 +3069,57 @@ tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
return 0;
}
/** Search for subject in list of TLS Certificate subjects */
int
tport_subject_search(char const *subject, su_strlst_t const *lst)
{
int idx, ilen;
const char *subjuri;
if (!subject || su_strmatch(tpn_any, subject))
return 1;
if (!lst)
return 0;
/* Check if subject is a URI */
if (su_casenmatch(subject,"sip:",4) || su_casenmatch(subject,"sips:",5))
subjuri = subject + su_strncspn(subject,5,":") + 1;
else
subjuri = NULL;
ilen = su_strlst_len(lst);
for (idx = 0; idx < ilen; idx++) {
const char *lsturi, *lststr;
lststr = su_strlst_item(lst, idx);
/* check if lststr is a URI (sips URI is an unacceptable cert subject) */
if (su_casenmatch(lststr,"sip:",4))
lsturi = lststr + su_strncspn(lststr,4,":") + 1;
else
lsturi = NULL;
/* Match two SIP Server Identities */
if (host_cmp(subjuri ? subjuri : subject, lsturi ? lsturi : lststr) == 0)
return 1;
#if 0
/* XXX - IETF drafts forbid wildcard certs */
if (!subjuri && !lsturi && su_strnmatch("*.", lststr, 2)) {
size_t urioffset = su_strncspn(subject, 64, ".");
if (urioffset) {
if (su_casematch(subject + urioffset, lststr+1))
return 1;
}
}
#endif
}
return 0;
}
/** Allocate message for N bytes,
* return message buffer as a iovec
*/
......@@ -3152,7 +3203,7 @@ int tport_recv_error_report(tport_t *self)
*
* @TAGS
* TPTAG_MTU(), TPTAG_REUSE(), TPTAG_CLOSE_AFTER(), TPTAG_SDWN_AFTER(),
* TPTAG_FRESH(), TPTAG_COMPARTMENT().
* TPTAG_FRESH(), TPTAG_COMPARTMENT(), TPTAG_X509_SUBJECT()
*/
tport_t *tport_tsend(tport_t *self,
msg_t *msg,
......@@ -4581,6 +4632,13 @@ tport_t *tport_by_addrinfo(tport_primary_t const *pri,
if (tport_is_shutdown(sub))
continue;
if (tport_has_tls(sub) && !su_casematch(tpn->tpn_canon, sub->tp_name->tpn_canon)) {
if (!tport_is_verified(sub))
continue;
if (!tport_subject_search(tpn->tpn_canon, sub->tp_subjects))
continue;
}
if (comp != sub->tp_name->tpn_comp)
continue;
......
......@@ -181,8 +181,10 @@ struct tport_s {
su_strlst_t *tp_subjects; /**< Transport Subjects.
*
* Subject Name(s) provided by the
* peer in a TLS connection (if secondary).
* Subject Name(s) provided by the peer
* in a TLS connection (if secondary).
* or matched against incoming
* connections (if primary).
*/
#define tp_protoname tp_name->tpn_proto
......
......@@ -281,20 +281,137 @@ tag_typedef_t tptag_compartment = PTRTAG_TYPEDEF(compartment);
tag_typedef_t tptag_tls_version = UINTTAG_TYPEDEF(tls_version);
/**@def TPTAG_TLS_VERIFY_PEER(x)
* @par Depreciated:
* Alias for TPTAG_TLS_VERIFY_POLICY(TPTLS_VERIFY_IN|TPTLS_VERIFY_OUT)
*
* @NEW_1_12_10.
*/
tag_typedef_t tptag_tls_verify_peer = UINTTAG_TYPEDEF(tls_verify_peer);
/**@def TPTAG_TLS_VERIFY_POLICY(x)
*
* The verification of certificates can be controlled:
* 0: no verify certificates;
* 1: on server mode, the certificate returned by client is checked
* if fail the TLS/SSL handshake is immediately terminated;
* 1: on client mode, the server certificate is verified
* if fail the TLS/SSL handshake is immediately terminated;
* @par Values:
* - #TPTLS_VERIFY_NONE:
* Do not verify Peer Certificates.
* - #TPTLS_VERIFY_IN:
* Drop incoming connections which fail signature verification
* against trusted certificate authorities. Peers must provide a
* certificate during the initial TLS Handshake.
* - #TPTLS_VERIFY_OUT:
* Drop outgoing connections which fail signature verification
* against trusted certificate authorities.
* - #TPTLS_VERIFY_ALL:
* Alias for (TPTLS_VERIFY_IN|TPTLS_VERIFY_OUT)
* - #TPTLS_VERIFY_SUBJECTS_IN:
* Match the certificate subject on incoming connections against
* a provided list. If no match is found, the connection is
* rejected. If no list is provided, subject checking is bypassed.
* Note: Implies #TPTLS_VERIFY_IN.
* - #TPTLS_VERIFY_SUBJECTS_OUT:
* Match the certificate subject on outgoing connections against
* a provided list. If no match is found, the connection is
* rejected.
* Note: Implies #TPTLS_VERIFY_OUT.
* - #TPTLS_VERIFY_SUBJECTS_ALL:
* Alias for (TPTLS_VERIFY_SUBJECTS_IN|TPTLS_VERIFY_SUBJECTS_OUT)
*
* Use with tport_tbind(), nua_create(), nta_agent_create(),
* nta_agent_add_tport(), nth_engine_create(), or initial nth_site_create().
* @par Used with
* tport_tbind(), nua_create(), nta_agent_create(), nta_agent_add_tport(),
* nth_engine_create(), initial nth_site_create(),
* TPTAG_TLS_VERIFY_SUBJECTS(), TPTAG_TLS_VERIFY_DEPTH().
*
* @NEW_1_12_10.
* @NEW_1_12_11.
*/
tag_typedef_t tptag_tls_verify_peer = UINTTAG_TYPEDEF(tls_verify_peer);
tag_typedef_t tptag_tls_verify_policy = UINTTAG_TYPEDEF(tls_verify_policy);
/**@def TPTAG_TLS_VERIFY_DEPTH(x)
*
* Define the maximum length of a valid certificate chain.
*
* @par Default
* 2
*
* @par Used with
* tport_tbind(), nua_create(), nta_agent_create(), nta_agent_add_tport(),
* nth_engine_create(), or initial nth_site_create().
*
* @par Parameter Type:
* unsigned int
*
* @NEW_1_12_11.
*/
tag_typedef_t tptag_tls_verify_depth = UINTTAG_TYPEDEF(tls_verify_depth);
/**@def TPTAG_TLS_VERIFY_DATE(x)
*
* Enable/Disable verification of notBefore and notAfter parameters of
* X.509 Certificates.
*
* @par Default
* Enabled
*
* @par Values
* - 0 - Disable date verification.
* - Non-Zero - Enable date verification.
*
* @par Used with
* tport_tbind(), nua_create(), nta_agent_create(), nta_agent_add_tport(),
* nth_engine_create(), or initial nth_site_create().
*
* @par Parameter Type:
* unsigned int
*
* @par Note
* This tag should be only used on devices which lack accurate timekeeping.
*
* @NEW_1_12_11.
*/
tag_typedef_t tptag_tls_verify_date = UINTTAG_TYPEDEF(tls_verify_date);
/**@def TPTAG_TLS_VERIFY_SUBJECTS(x)
*
* Incoming TLS connections must provide a trusted X.509 certificate.
* The character strings provided with this tag are matched against
* the subjects from the trusted certificate. If a match is not found,
* the connection is automatically rejected.
*
* @par Used with
* tport_tbind(), nua_create(), nta_agent_create(), nta_agent_add_tport(),
* nth_engine_create(), initial nth_site_create(),
* TPTLS_VERIFY_SUBJECTS_IN
*
* @par Parameter Type:
* void const * (actually su_strlst_t const *)
*
* @par Values
* - SIP Identity - sip:example.com or sip:username@example.com
* - DNS - sip.example.com
* - IP Address - Both IPv4 and IPv6 Supported
*
* @NEW_1_12_11.
*/
tag_typedef_t tptag_tls_verify_subjects = PTRTAG_TYPEDEF(tls_verify_subjects);
#if 0
/**@def TPTAG_X509_SUBJECT(x)
*
* Requires that a message be sent over a TLS transport with trusted X.509
* certificate. The character string provided must match against a subject
* from the trusted certificate.
*
* @par Used with
* tport_tsend(), TPTLS_VERIFY_SUBJECTS_OUT
*
* @par Parameter Type:
* char const *
*
* @par Values
* - Refer to TPTAG_TLS_VERIFY_SUBJECTS()
*
* @note Not Implemented.
*/
#endif
/**@def TPTAG_QUEUESIZE(x)
*
......
......@@ -56,7 +56,6 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_SIGPIPE
#include <signal.h>
......@@ -65,6 +64,7 @@
#include "tport_tls.h"
char const tls_version[] = OPENSSL_VERSION_TEXT;
int tls_ex_data_idx = -1; /* see SSL_get_ex_new_index(3ssl) */
enum { tls_master = 0, tls_slave = 1};
......@@ -75,9 +75,12 @@ struct tls_s {
BIO *bio_con;
unsigned int type:1,
accept:1,
verify_outgoing:1,
verify_incoming:1,
verified:1;
verify_outgoing:1,
verify_subj_in:1,
verify_subj_out:1,
verify_date:1,
x509_verified:1;
/* Receiving */
int read_events;
......@@ -90,7 +93,7 @@ struct tls_s {
size_t write_buffer_len;
/* Host names */
su_strlst_t *subject;
su_strlst_t *subjects;
};
enum { tls_buffer_size = 16384 };
......@@ -162,13 +165,44 @@ int tls_verify_cb(int ok, X509_STORE_CTX *store)
X509 *cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
int sslidx = SSL_get_ex_data_X509_STORE_CTX_idx();
SSL *ssl = X509_STORE_CTX_get_ex_data(store, sslidx);
tls_t *tls = SSL_get_ex_data(ssl, tls_ex_data_idx);
assert(tls);
#define TLS_VERIFY_CB_CLEAR_ERROR(OK,ERR,STORE) \
do {\
OK = 1;\
ERR = X509_V_OK;\
X509_STORE_CTX_set_error(STORE,ERR);\
} while (0)
if (tls->accept && !tls->verify_incoming)
TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);
else if (!tls->accept && !tls->verify_outgoing)
TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);
else switch (err) {
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CRL_HAS_EXPIRED:
if (!tls->verify_date)
TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);
default:
break;
}
if (!ok) {
SU_DEBUG_3(("-Error with certificate at depth: %i\n", depth));
X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
SU_DEBUG_3((" issuer = %s\n", data));
X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
SU_DEBUG_3((" subject = %s\n", data));
SU_DEBUG_3((" err %i:%s\n", err, X509_verify_cert_error_string(err)));
}
SU_DEBUG_1(("-Error with certificate at depth: %i\n", depth));
X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
SU_DEBUG_1((" issuer = %s\n", data));
X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
SU_DEBUG_1((" subject = %s\n", data));
SU_DEBUG_1((" err %i:%s\n", err, X509_verify_cert_error_string(err)));
}
return ok;
......@@ -178,11 +212,14 @@ static
int tls_init_context(tls_t *tls, tls_issues_t const *ti)
{
static int initialized = 0;
int verify;
if (!initialized) {
initialized = 1;
SSL_library_init();
SSL_load_error_strings();
tls_ex_data_idx = SSL_get_ex_new_index(0, \
"sofia-sip private data", NULL, NULL, NULL);
if (ti->randFile &&
!RAND_load_file(ti->randFile, 1024 * 1024)) {
......@@ -267,13 +304,20 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
return -1;
}
SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
/* corresponds to (enum tport_tls_verify_policy) */
tls->verify_incoming = (ti->policy & 0x1) ? 1 : 0;
tls->verify_outgoing = (ti->policy & 0x2) ? 1 : 0;
tls->verify_subj_in = (ti->policy & 0x4) ? tls->verify_incoming : 0;
tls->verify_subj_out = (ti->policy & 0x8) ? tls->verify_outgoing : 0;
tls->verify_date = (ti->verify_date) ? 1 : 0;
SSL_CTX_set_verify(tls->ctx,
ti->verify_peer == 1 ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
tls_verify_cb);
if (tls->verify_incoming)
verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
else
verify = SSL_VERIFY_NONE;
tls->verify_incoming = tls->verify_outgoing = ti->verify_peer ? 1 : 0;
SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
SSL_CTX_set_verify(tls->ctx, verify, tls_verify_cb);
if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) {
SU_DEBUG_1(("%s: error setting cipher list\n", "tls_init_context"));
......@@ -360,13 +404,20 @@ tls_t *tls_init_master(tls_issues_t *ti)
return tls;
}
tls_t *tls_clone(tls_t *master, int sock, int accept)
tls_t *tls_init_secondary(tls_t *master, int sock, int accept)
{
tls_t *tls = tls_create(tls_slave);
if (tls) {
tls->ctx = master->ctx;
tls->type = master->type;
tls->accept = accept ? 1 : 0;
tls->verify_outgoing = master->verify_outgoing;
tls->verify_incoming = master->verify_incoming;
tls->verify_subj_out = master->verify_subj_out;
tls->verify_subj_in = master->verify_subj_in;
tls->verify_date = master->verify_date;
tls->x509_verified = master->x509_verified;
if (!(tls->read_buffer = su_alloc(tls->home, tls_buffer_size)))
su_home_unref(tls->home), tls = NULL;
......@@ -380,7 +431,7 @@ tls_t *tls_clone(tls_t *master, int sock, int accept)
tls->con = SSL_new(tls->ctx);
if (tls->con == NULL) {
tls_log_errors(1, "tls_clone", 0);
tls_log_errors(1, "tls_init_secondary", 0);
tls_free(tls);
errno = EIO;
return NULL;
......@@ -388,26 +439,15 @@ tls_t *tls_clone(tls_t *master, int sock, int accept)
SSL_set_bio(tls->con, tls->bio_con, tls->bio_con);
SSL_set_mode(tls->con, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_set_ex_data(tls->con, tls_ex_data_idx, tls);
su_setblocking(sock, 0);
return tls;
}
tls_t *tls_init_slave(tls_t *master, int sock)
{
int accept;
return tls_clone(master, sock, accept = 1);
}
tls_t *tls_init_client(tls_t *master, int sock)
{
int accept;
return tls_clone(master, sock, accept = 0);
}
static
int tls_post_connection_check(tls_t *tls)
su_inline
int tls_post_connection_check(tport_t *self, tls_t *tls)
{
X509 *cert;
int extcount;
......@@ -416,13 +456,22 @@ int tls_post_connection_check(tls_t *tls)
if (!tls) return -1;
cert = SSL_get_peer_certificate(tls->con);
if (!cert)
return X509_V_OK;
if (!cert) {
SU_DEBUG_7(("%s(%p): Peer did not provide X.509 Certificate.\n",
__func__, self));
if (self->tp_accepted && tls->verify_incoming)
return X509_V_ERR_CERT_UNTRUSTED;
else if (!self->tp_accepted && tls->verify_outgoing)
return X509_V_ERR_CERT_UNTRUSTED;
else
return X509_V_OK;
}
extcount = X509_get_ext_count(cert);
tls->subjects = su_strlst_create(tls->home);
if (!tls->subjects)
return X509_V_ERR_OUT_OF_MEM;
if (!tls->subject)
tls->subject = su_strlst_create(tls->home);
extcount = X509_get_ext_count(cert);
/* Find matching subjectAltName.DNS */
for (i = 0; i < extcount; i++) {
......@@ -446,13 +495,11 @@ int tls_post_connection_check(tls_t *tls)
for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
value = sk_CONF_VALUE_value(values, j);
if (strcmp(value->name, "DNS") == 0)
su_strlst_dup_append(tls->subject, value->value);
else if (strcmp(value->name, "URI") == 0) {
char *uri = su_strlst_dup_append(tls->subject, value->value);
char const *url = strchr(uri, ':');
if (url++)
su_strlst_append(tls->subject, url);
}
su_strlst_dup_append(tls->subjects, value->value);
if (strcmp(value->name, "IP") == 0)
su_strlst_dup_append(tls->subjects, value->value);
else if (strcmp(value->name, "URI") == 0)
su_strlst_dup_append(tls->subjects, value->value);
}
}
......@@ -465,15 +512,15 @@ int tls_post_connection_check(tls_t *tls)
if (subject) {
if (X509_NAME_get_text_by_NID(subject, NID_commonName,
name, sizeof name) > 0) {
usize_t k, N = su_strlst_len(tls->subject);
usize_t k, N = su_strlst_len(tls->subjects);
name[(sizeof name) - 1] = '\0';
for (k = 0; k < N; k++)
if (strcasecmp(su_strlst_item(tls->subject, k), name) == 0)
if (su_casematch(su_strlst_item(tls->subjects, k), name) == 0)
break;
if (k == N)
su_strlst_dup_append(tls->subject, name);
if (k >= N)
su_strlst_dup_append(tls->subjects, name);
}
}
}
......@@ -482,13 +529,64 @@ int tls_post_connection_check(tls_t *tls)
error = SSL_get_verify_result(tls->con);
if (error == X509_V_OK)
tls->verified = 1;
if (cert && error == X509_V_OK)
tls->x509_verified = 1;
if (tport_log->log_level >= 7) {
int i, len = su_strlst_len(tls->subjects);
for (i=0; i < len; i++)