mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-10 22:49:43 +00:00
Thu Jan 15 09:50:45 CST 2009 Jarod Neuner <janeuner@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@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. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11830 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
27a5a679be
commit
38dabb3635
@ -1 +1 @@
|
||||
Wed Feb 11 11:03:24 CST 2009
|
||||
Wed Feb 11 11:03:50 CST 2009
|
||||
|
@ -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,21 +281,138 @@ tag_typedef_t tptag_compartment = PTRTAG_TYPEDEF(compartment);
|
||||
tag_typedef_t tptag_tls_version = UINTTAG_TYPEDEF(tls_version);
|
||||
|
||||
/**@def TPTAG_TLS_VERIFY_PEER(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;
|
||||
*
|
||||
* Use with tport_tbind(), nua_create(), nta_agent_create(),
|
||||
* nta_agent_add_tport(), nth_engine_create(), or initial nth_site_create().
|
||||
* @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:
|
||||
* @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)
|
||||
*
|
||||
* @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_11.
|
||||
*/
|
||||
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)
|
||||
*
|
||||
* Specify the number of messages that can be queued per connection.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
tls->verify_incoming = tls->verify_outgoing = ti->verify_peer ? 1 : 0;
|
||||
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,14 +456,23 @@ 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;
|
||||
}
|
||||
|
||||
tls->subjects = su_strlst_create(tls->home);
|
||||
if (!tls->subjects)
|
||||
return X509_V_ERR_OUT_OF_MEM;
|
||||
|
||||
extcount = X509_get_ext_count(cert);
|
||||
|
||||
if (!tls->subject)
|
||||
tls->subject = su_strlst_create(tls->home);
|
||||
|
||||
/* Find matching subjectAltName.DNS */
|
||||
for (i = 0; i < extcount; i++) {
|
||||
X509_EXTENSION *ext;
|
||||
@ -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++)
|
||||
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 @@ ssize_t tls_read(tls_t *tls)
|
||||
|
||||
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 @@ ssize_t tls_write(tls_t *tls, void *buf, size_t size)
|
||||
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 @@ int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
|
||||
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 @@ int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
|
||||
|
||||
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 @@ int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
|
||||
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);
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user