[Freeswitch-svn] [commit] r11830 - in freeswitch/trunk/libs/sofia-sip: . libsofia-sip-ua/tport libsofia-sip-ua/tport/sofia-sip
FreeSWITCH SVN
mikej at freeswitch.org
Wed Feb 11 09:03:59 PST 2009
Author: mikej
Date: Wed Feb 11 11:03:59 2009
New Revision: 11830
Log:
Thu Jan 15 09:50:45 CST 2009 Jarod Neuner <janeuner at networkharbor.com>
* 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 at example.com
sip:alice at example.com
sips:alice at 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.
Modified:
freeswitch/trunk/libs/sofia-sip/.update
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
Modified: freeswitch/trunk/libs/sofia-sip/.update
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/.update (original)
+++ freeswitch/trunk/libs/sofia-sip/.update Wed Feb 11 11:03:59 2009
@@ -1 +1 @@
-Wed Feb 11 11:03:24 CST 2009
+Wed Feb 11 11:03:50 CST 2009
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h Wed Feb 11 11:03:59 2009
@@ -339,7 +339,11 @@
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 *);
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h Wed Feb 11 11:03:59 2009
@@ -186,18 +186,59 @@
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;
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c Wed Feb 11 11:03:59 2009
@@ -273,7 +273,7 @@
/** 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 @@
*
* @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 @@
}
/** 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 @@
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 @@
*
* @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 @@
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;
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h Wed Feb 11 11:03:59 2009
@@ -181,8 +181,10 @@
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
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c Wed Feb 11 11:03:59 2009
@@ -281,20 +281,137 @@
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 at 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)
*
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c Wed Feb 11 11:03:59 2009
@@ -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 @@
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 @@
size_t write_buffer_len;
/* Host names */
- su_strlst_t *subject;
+ su_strlst_t *subjects;
};
enum { tls_buffer_size = 16384 };
@@ -162,13 +165,44 @@
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 @@
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 @@
return -1;
}
- SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
-
- SSL_CTX_set_verify(tls->ctx,
- ti->verify_peer == 1 ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
- tls_verify_cb);
+ /* 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;
+
+ 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 @@
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->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 @@
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 @@
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 @@
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 @@
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 @@
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++)
+ SU_DEBUG_7(("%s(%p): Peer Certificate Subject %i: %s\n", \
+ __func__, self, i, su_strlst_item(tls->subjects, i)));
+ if (i == 0)
+ SU_DEBUG_7(("%s(%p): Peer Certificate provided no usable subjects.\n",
+ __func__, self));
+ }
+
+ /* Verify incoming connections */
+ if (self->tp_accepted) {
+ if (!tls->verify_incoming)
+ return X509_V_OK;
+
+ if (!tls->x509_verified)
+ return error;
+
+ if (tls->verify_subj_in) {
+ su_strlst_t const *subjects = self->tp_pri->pri_primary->tp_subjects;
+ int i, items;
+
+ items = subjects ? su_strlst_len(subjects) : 0;
+ if (items == 0)
+ return X509_V_OK;
+
+ for (i=0; i < items; i++) {
+ if (tport_subject_search(su_strlst_item(subjects, i), tls->subjects))
+ return X509_V_OK;
+ }
+ SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (incoming connection)\n", \
+ __func__, self));
+
+ return X509_V_ERR_CERT_UNTRUSTED;
+ }
+ }
+ /* Verify outgoing connections */
+ else {
+ char const *subject = self->tp_canon;
+ if (!tls->verify_outgoing)
+ return X509_V_OK;
+
+ if (!tls->x509_verified || !subject)
+ return error;
+
+ if (tls->verify_subj_out) {
+ if (tport_subject_search(subject, tls->subjects))
+ return X509_V_OK; /* Subject match found in verified certificate chain */
+ SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (%s)\n", \
+ __func__, self, subject));
+
+ return X509_V_ERR_CERT_UNTRUSTED;
+ }
+ }
- if (tls->accept && !tls->verify_incoming)
- return X509_V_OK;
- else if (!tls->accept && !tls->verify_outgoing)
- return X509_V_OK;
return error;
}
@@ -547,7 +645,7 @@
if (0)
SU_DEBUG_1(("tls_read(%p) called on %s (events %u)\n", (void *)tls,
- tls->accept ? "server" : "client",
+ tls->type ? "master" : "slave",
tls->read_events));
if (tls->read_buffer_len)
@@ -607,7 +705,7 @@
if (0)
SU_DEBUG_1(("tls_write(%p, %p, "MOD_ZU") called on %s\n",
(void *)tls, buf, size,
- tls && tls->type == tls_slave ? "server" : "client"));
+ tls && tls->type == tls_slave ? "master" : "slave"));
if (tls == NULL || buf == NULL) {
errno = EINVAL;
@@ -731,7 +829,7 @@
if (self->tp_is_connected == 0) {
int ret, status;
- ret = tls->accept ? SSL_accept(tls->con) : SSL_connect(tls->con);
+ ret = self->tp_accepted ? SSL_accept(tls->con) : SSL_connect(tls->con);
status = SSL_get_error(tls->con, ret);
switch (status) {
@@ -751,7 +849,8 @@
case SSL_ERROR_NONE:
/* TLS Handshake complete */
- if ( tls_post_connection_check(tls) == X509_V_OK ) {
+ status = tls_post_connection_check(self, tls);
+ if ( status == X509_V_OK ) {
su_wait_t wait[1] = {SU_WAIT_INIT};
tport_master_t *mr = self->tp_master;
@@ -770,9 +869,8 @@
tls->read_events = SU_WAIT_IN;
tls->write_events = 0;
self->tp_is_connected = 1;
- self->tp_verified = tls->verified;
- self->tp_subjects = tls->subject == NULL ? NULL :
- su_strlst_dup(self->tp_home, tls->subject);
+ self->tp_verified = tls->x509_verified;
+ self->tp_subjects = tls->subjects;
if (tport_has_queued(self))
tport_send_event(self);
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h Wed Feb 11 11:03:59 2009
@@ -50,9 +50,9 @@
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 @@
} 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);
Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c (original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c Wed Feb 11 11:03:59 2009
@@ -95,9 +95,6 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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",
More information about the Freeswitch-svn
mailing list