[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