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)
*
......
This diff is collapsed.
......@@ -50,9 +50,9 @@ typedef struct tls_s tls_t;
extern char const tls_version[];
typedef struct tls_issues_s {
int verify_peer; /* 0: no verify certificate, *
* 1: if fail the TLS/SSL handshake is terminated. */
int verify_depth; /* if 0, then do nothing */
unsigned policy; /* refer to tport_tag.h, tport_tls_verify_policy */
unsigned verify_depth;/* if 0, revert to default (2) */
unsigned verify_date; /* if 0, notBefore and notAfter dates are ignored */
int configured; /* If non-zero, complain about certificate errors */
char *cert; /* CERT file name. File format is PEM */
char *key; /* Private key file. PEM format */
......@@ -78,8 +78,7 @@ typedef struct tport_tls_primary_s {
} tport_tls_primary_t;
tls_t *tls_init_master(tls_issues_t *tls_issues);
tls_t *tls_init_slave(tls_t *tls_master, int sock);
tls_t *tls_init_client(tls_t *tls_master, int sock);
tls_t *tls_init_secondary(tls_t *tls_master, int sock, int accept);
void tls_free(tls_t *tls);
int tls_get_socket(tls_t *tls);
ssize_t tls_read(tls_t *tls);
......
......@@ -95,9 +95,6 @@ static ssize_t tport_tls_send(tport_t const *self, msg_t *msg,
static int tport_tls_accept(tport_primary_t *pri, int events);
static tport_t *tport_tls_connect(tport_primary_t *pri, su_addrinfo_t *ai,
tp_name_t const *tpn);
#if notyet
static void tport_tls_deliver(tport_t *self, msg_t *msg, su_time_t now);
#endif
tport_vtable_t const tport_tls_vtable =
{
......@@ -171,6 +168,10 @@ static int tport_tls_init_master(tport_primary_t *pri,
char const *path = NULL;
unsigned tls_version = 1;
unsigned tls_verify = 0;
unsigned tls_policy = TPTLS_VERIFY_NONE;
unsigned tls_depth = 0;
unsigned tls_date = 1;
su_strlst_t const *tls_subjects = NULL;
su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
tls_issues_t ti = {0};
......@@ -183,6 +184,10 @@ static int tport_tls_init_master(tport_primary_t *pri,
TPTAG_CERTIFICATE_REF(path),
TPTAG_TLS_VERSION_REF(tls_version),
TPTAG_TLS_VERIFY_PEER_REF(tls_verify),
TPTAG_TLS_VERIFY_POLICY_REF(tls_policy),
TPTAG_TLS_VERIFY_DEPTH_REF(tls_depth),
TPTAG_TLS_VERIFY_DATE_REF(tls_date),
TPTAG_TLS_VERIFY_SUBJECTS_REF(tls_subjects),
TAG_END());
if (!path) {
......@@ -193,8 +198,9 @@ static int tport_tls_init_master(tport_primary_t *pri,
}
if (path) {
ti.verify_peer = tls_verify;
ti.verify_depth = 2;
ti.policy = tls_policy | (tls_verify ? TPTLS_VERIFY_ALL : 0);
ti.verify_depth = tls_depth;
ti.verify_date = tls_date;
ti.configured = path != tbf;
ti.randFile = su_sprintf(autohome, "%s/%s", path, "tls_seed.dat");
ti.key = su_sprintf(autohome, "%s/%s", path, "agent.pem");
......@@ -225,6 +231,8 @@ static int tport_tls_init_master(tport_primary_t *pri,
return *return_culprit = "tls_init_master", -1;
}
if (tls_subjects)
pri->pri_primary->tp_subjects = su_strlst_dup(pri->pri_home, tls_subjects);
pri->pri_has_tls = 1;
return 0;
......@@ -247,11 +255,9 @@ static int tport_tls_init_secondary(tport_t *self, int socket, int accepted,
if (tport_tcp_init_secondary(self, socket, accepted, return_reason) < 0)
return -1;
if (accepted) {
tlstp->tlstp_context = tls_init_slave(master, socket);
if (!tlstp->tlstp_context)
return *return_reason = "tls_init_slave", -1;
}
tlstp->tlstp_context = tls_init_secondary(master, socket, accepted);
if (!tlstp->tlstp_context)
return *return_reason = "tls_init_slave", -1;
return 0;
}
......@@ -439,20 +445,12 @@ ssize_t tport_tls_send(tport_t const *self,
msg_iovec_t iov[],
size_t iovlen)
{
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
tport_tls_t *tlstp = (tport_tls_t *)self;
enum { TLSBUFSIZE = 2048 };
size_t i, j, n, m, size = 0;
ssize_t nerror;
int oldmask, mask;
if (tlstp->tlstp_context == NULL) {
tls_t *master = tlspri->tlspri_master;
tlstp->tlstp_context = tls_init_client(master, self->tp_socket);
if (!tlstp->tlstp_context)
return -1;
}
oldmask = tls_events(tlstp->tlstp_context, self->tp_events);
#if 0
......@@ -560,8 +558,6 @@ int tport_tls_accept(tport_primary_t *pri, int events)
return 0;
}
else {
tport_tls_t *tlstp = (tport_tls_t *)self;
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
int events = SU_WAIT_IN|SU_WAIT_ERR|SU_WAIT_HUP;
SU_CANONIZE_SOCKADDR(su);
......@@ -575,8 +571,6 @@ int tport_tls_accept(tport_primary_t *pri, int events)
self->tp_conn_orient = 1;
self->tp_is_connected = 0;
tlstp->tlstp_context = tls_init_slave(tlspri->tlspri_master, s);
SU_DEBUG_5(("%s(%p): new connection from " TPN_FORMAT "\n",
__func__, (void *)self, TPN_ARGS(self->tp_name)));
......@@ -640,14 +634,9 @@ tport_t *tport_tls_connect(tport_primary_t *pri,
goto sys_error;
}
if (tport_setname(self, tpn->tpn_proto, ai, tpn->tpn_canon) != -1
&&
tport_register_secondary(self, tls_connect, events) != -1) {
tport_tls_t *tlstp = (tport_tls_t *)self;
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
tlstp->tlstp_context = tls_init_client(tlspri->tlspri_master, s);
}
else
if (tport_setname(self, tpn->tpn_proto, ai, tpn->tpn_canon) == -1)
goto sys_error;
else if (tport_register_secondary(self, tls_connect, events) == -1)
goto sys_error;
SU_DEBUG_5(("%s(%p): connecting to " TPN_FORMAT "\n",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment