summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2017-01-11 01:41:31 +0000
committerLiong Sauw Ming <ming@teluu.com>2017-01-11 01:41:31 +0000
commit95545ba14b27fdfd505c5c7f9f66660dba68008b (patch)
tree431e728b7bb2b3cb87bc272d2d2c5463760eafdd
parent9c135526de34da4f5b477021599bc00f61f1c1a3 (diff)
Fixed #1960: Export SIP transport TLS state and TLS certificate info to PJSUA2
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5518 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip-apps/src/swig/symbols.i4
-rw-r--r--pjsip-apps/src/swig/symbols.lst2
-rw-r--r--pjsip/include/pjsua2/endpoint.hpp160
-rw-r--r--pjsip/src/pjsua2/endpoint.cpp93
4 files changed, 258 insertions, 1 deletions
diff --git a/pjsip-apps/src/swig/symbols.i b/pjsip-apps/src/swig/symbols.i
index 03bfa89f..5edacf2b 100644
--- a/pjsip-apps/src/swig/symbols.i
+++ b/pjsip-apps/src/swig/symbols.i
@@ -34,6 +34,10 @@ typedef enum pj_ssl_cipher {PJ_TLS_UNKNOWN_CIPHER = -1, PJ_TLS_NULL_WITH_NULL_NU
typedef enum pj_ssl_sock_proto {PJ_SSL_SOCK_PROTO_DEFAULT = 0, PJ_SSL_SOCK_PROTO_SSL2 = 1 << 0, PJ_SSL_SOCK_PROTO_SSL3 = 1 << 1, PJ_SSL_SOCK_PROTO_TLS1 = 1 << 2, PJ_SSL_SOCK_PROTO_TLS1_1 = 1 << 3, PJ_SSL_SOCK_PROTO_TLS1_2 = 1 << 4, PJ_SSL_SOCK_PROTO_SSL23 = (1 << 16) - 1, PJ_SSL_SOCK_PROTO_DTLS1 = 1 << 16} pj_ssl_sock_proto;
+typedef enum pj_ssl_cert_name_type {PJ_SSL_CERT_NAME_UNKNOWN = 0, PJ_SSL_CERT_NAME_RFC822, PJ_SSL_CERT_NAME_DNS, PJ_SSL_CERT_NAME_URI, PJ_SSL_CERT_NAME_IP} pj_ssl_cert_name_type;
+
+typedef enum pj_ssl_cert_verify_flag_t {PJ_SSL_CERT_ESUCCESS = 0, PJ_SSL_CERT_EISSUER_NOT_FOUND = (1 << 0), PJ_SSL_CERT_EUNTRUSTED = (1 << 1), PJ_SSL_CERT_EVALIDITY_PERIOD = (1 << 2), PJ_SSL_CERT_EINVALID_FORMAT = (1 << 3), PJ_SSL_CERT_EINVALID_PURPOSE = (1 << 4), PJ_SSL_CERT_EISSUER_MISMATCH = (1 << 5), PJ_SSL_CERT_ECRL_FAILURE = (1 << 6), PJ_SSL_CERT_EREVOKED = (1 << 7), PJ_SSL_CERT_ECHAIN_TOO_LONG = (1 << 8), PJ_SSL_CERT_EIDENTITY_NOT_MATCH = (1 << 30), PJ_SSL_CERT_EUNKNOWN = (1 << 31)} pj_ssl_cert_verify_flag_t;
+
typedef enum pj_stun_nat_type {PJ_STUN_NAT_TYPE_UNKNOWN, PJ_STUN_NAT_TYPE_ERR_UNKNOWN, PJ_STUN_NAT_TYPE_OPEN, PJ_STUN_NAT_TYPE_BLOCKED, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP, PJ_STUN_NAT_TYPE_FULL_CONE, PJ_STUN_NAT_TYPE_SYMMETRIC, PJ_STUN_NAT_TYPE_RESTRICTED, PJ_STUN_NAT_TYPE_PORT_RESTRICTED} pj_stun_nat_type;
typedef enum pj_turn_tp_type {PJ_TURN_TP_UDP = 17, PJ_TURN_TP_TCP = 6, PJ_TURN_TP_TLS = 255} pj_turn_tp_type;
diff --git a/pjsip-apps/src/swig/symbols.lst b/pjsip-apps/src/swig/symbols.lst
index 35bed882..651e78d4 100644
--- a/pjsip-apps/src/swig/symbols.lst
+++ b/pjsip-apps/src/swig/symbols.lst
@@ -2,7 +2,7 @@ pj/types.h pj_status_t pj_constants_ pj_uint8_t pj_int32_t pj_uint32_t pj_uint
pj/file_io.h pj_file_access
pj/log.h pj_log_decoration
pj/sock_qos.h pj_qos_type pj_qos_flag pj_qos_wmm_prio pj_qos_params
-pj/ssl_sock.h pj_ssl_cipher pj_ssl_sock_proto
+pj/ssl_sock.h pj_ssl_cipher pj_ssl_sock_proto pj_ssl_cert_name_type pj_ssl_cert_verify_flag_t
pjnath/nat_detect.h pj_stun_nat_type
pjnath/turn_session.h pj_turn_tp_type
diff --git a/pjsip/include/pjsua2/endpoint.hpp b/pjsip/include/pjsua2/endpoint.hpp
index 4fdd0405..da777868 100644
--- a/pjsip/include/pjsua2/endpoint.hpp
+++ b/pjsip/include/pjsua2/endpoint.hpp
@@ -124,6 +124,140 @@ struct OnTimerParam
};
/**
+ * SSL certificate type and name structure.
+ */
+struct SslCertName
+{
+ pj_ssl_cert_name_type type; /**< Name type */
+ string name; /**< The name */
+};
+
+/**
+ * SSL certificate information.
+ */
+struct SslCertInfo
+{
+ unsigned version; /**< Certificate version */
+ unsigned char serialNo[20]; /**< Serial number, array
+ of octets, first index
+ is MSB */
+ string subjectCn; /**< Subject common name */
+ string subjectInfo; /**< One line subject, fields
+ are separated by slash, e.g:
+ "CN=sample.org/OU=HRD" */
+
+ string issuerCn; /**< Issuer common name */
+ string issuerInfo; /**< One line subject, fields
+ are separated by slash */
+
+ TimeVal validityStart; /**< Validity start */
+ TimeVal validityEnd; /**< Validity end */
+ bool validityGmt; /**< Flag if validity
+ date/time use GMT */
+
+ vector<SslCertName> subjectAltName; /**< Subject alternative
+ name extension */
+
+ string raw; /**< Raw certificate in PEM
+ format, only available
+ for remote certificate */
+
+public:
+ /**
+ * Check if the info is set with empty values.
+ *
+ * @return True if the info is empty.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pj_ssl_cert_info &info);
+};
+
+/**
+ * TLS transport information.
+ */
+struct TlsInfo
+{
+ /**
+ * Describes whether secure socket connection is established, i.e: TLS/SSL
+ * handshaking has been done successfully.
+ */
+ bool established;
+
+ /**
+ * Describes secure socket protocol being used, see #pj_ssl_sock_proto.
+ * Use bitwise OR operation to combine the protocol type.
+ */
+ unsigned protocol;
+
+ /**
+ * Describes cipher suite being used, this will only be set when connection
+ * is established.
+ */
+ pj_ssl_cipher cipher;
+
+ /**
+ * Describes cipher name being used, this will only be set when connection
+ * is established.
+ */
+ string cipherName;
+
+ /**
+ * Describes local address.
+ */
+ SocketAddress localAddr;
+
+ /**
+ * Describes remote address.
+ */
+ SocketAddress remoteAddr;
+
+ /**
+ * Describes active local certificate info. Use SslCertInfo.isEmpty()
+ * to check if the local cert info is available.
+ */
+ SslCertInfo localCertInfo;
+
+ /**
+ * Describes active remote certificate info. Use SslCertInfo.isEmpty()
+ * to check if the remote cert info is available.
+ */
+ SslCertInfo remoteCertInfo;
+
+ /**
+ * Status of peer certificate verification.
+ */
+ unsigned verifyStatus;
+
+ /**
+ * Error messages (if any) of peer certificate verification, based on
+ * the field verifyStatus above.
+ */
+ StringVector verifyMsgs;
+
+public:
+ /**
+ * Constructor.
+ */
+ TlsInfo();
+
+ /**
+ * Check if the info is set with empty values.
+ *
+ * @return True if the info is empty.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsip_tls_state_info &info);
+};
+
+/**
* Parameter of Endpoint::onTransportState() callback.
*/
struct OnTransportStateParam
@@ -132,6 +266,11 @@ struct OnTransportStateParam
* The transport handle.
*/
TransportHandle hnd;
+
+ /**
+ * The transport type.
+ */
+ string type;
/**
* Transport current state.
@@ -142,6 +281,12 @@ struct OnTransportStateParam
* The last error code related to the transport state.
*/
pj_status_t lastError;
+
+ /**
+ * TLS transport info, only used if transport type is TLS. Use
+ * TlsInfo.isEmpty() to check if this info is available.
+ */
+ TlsInfo tlsInfo;
};
/**
@@ -1029,6 +1174,21 @@ public:
* @param id Transport ID.
*/
void transportClose(TransportId id) throw(Error);
+
+ /**
+ * Start graceful shutdown procedure for this transport handle. After
+ * graceful shutdown has been initiated, no new reference can be
+ * obtained for the transport. However, existing objects that currently
+ * uses the transport may still use this transport to send and receive
+ * packets. After all objects release their reference to this transport,
+ * the transport will be destroyed immediately.
+ *
+ * Note: application normally uses this API after obtaining the handle
+ * from onTransportState() callback.
+ *
+ * @param tp The transport.
+ */
+ void transportShutdown(TransportHandle tp) throw(Error);
/*************************************************************************
* Call operations
diff --git a/pjsip/src/pjsua2/endpoint.cpp b/pjsip/src/pjsua2/endpoint.cpp
index a66cfcf1..163e292f 100644
--- a/pjsip/src/pjsua2/endpoint.cpp
+++ b/pjsip/src/pjsua2/endpoint.cpp
@@ -44,6 +44,82 @@ Endpoint *Endpoint::instance_;
///////////////////////////////////////////////////////////////////////////////
+TlsInfo::TlsInfo()
+{
+ pj_bzero(this, sizeof(TlsInfo));
+}
+
+bool TlsInfo::isEmpty() const
+{
+ TlsInfo dummy;
+
+ pj_bzero(&dummy, sizeof(dummy));
+ return ((pj_memcmp(this, &dummy, sizeof(dummy)) == 0)? true: false);
+}
+
+void TlsInfo::fromPj(const pjsip_tls_state_info &info)
+{
+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
+ pj_ssl_sock_info *ssock_info = info.ssl_sock_info;
+ char straddr[PJ_INET6_ADDRSTRLEN+10];
+ const char *verif_msgs[32];
+ unsigned verif_msg_cnt;
+
+ established = PJ2BOOL(ssock_info->established);
+ protocol = ssock_info->proto;
+ cipher = ssock_info->cipher;
+ cipherName = pj_ssl_cipher_name(ssock_info->cipher);
+ pj_sockaddr_print(&ssock_info->local_addr, straddr, sizeof(straddr), 3);
+ localAddr = straddr;
+ pj_sockaddr_print(&ssock_info->remote_addr, straddr, sizeof(straddr),3);
+ remoteAddr = straddr;
+ verifyStatus = ssock_info->verify_status;
+ if (ssock_info->local_cert_info)
+ localCertInfo.fromPj(*ssock_info->local_cert_info);
+ if (ssock_info->remote_cert_info)
+ remoteCertInfo.fromPj(*ssock_info->remote_cert_info);
+
+ /* Dump server TLS certificate verification result */
+ verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
+ pj_ssl_cert_get_verify_status_strings(ssock_info->verify_status,
+ verif_msgs, &verif_msg_cnt);
+ for (unsigned i = 0; i < verif_msg_cnt; ++i) {
+ verifyMsgs.push_back(verif_msgs[i]);
+ }
+#endif
+}
+
+bool SslCertInfo::isEmpty() const
+{
+ SslCertInfo dummy;
+
+ pj_bzero(&dummy, sizeof(dummy));
+ return ((pj_memcmp(this, &dummy, sizeof(dummy)) == 0)? true: false);
+}
+
+void SslCertInfo::fromPj(const pj_ssl_cert_info &info)
+{
+ version = info.version;
+ pj_memcpy(serialNo, info.serial_no, sizeof(info.serial_no));
+ subjectCn = pj2Str(info.subject.cn);
+ subjectInfo = pj2Str(info.subject.info);
+ issuerCn = pj2Str(info.issuer.cn);
+ issuerInfo = pj2Str(info.issuer.info);
+ validityStart.fromPj(info.validity.start);
+ validityEnd.fromPj(info.validity.end);
+ validityGmt = PJ2BOOL(info.validity.gmt);
+ raw = pj2Str(info.raw);
+
+ for (unsigned i = 0; i < info.subj_alt_name.cnt; i++) {
+ SslCertName cname;
+ cname.type = info.subj_alt_name.entry[i].type;
+ cname.name = pj2Str(info.subj_alt_name.entry[i].name);
+ subjectAltName.push_back(cname);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
UaConfig::UaConfig()
: mainThreadOnly(false)
{
@@ -558,8 +634,20 @@ void Endpoint::on_transport_state( pjsip_transport *tp,
OnTransportStateParam prm;
prm.hnd = (TransportHandle)tp;
+ prm.type = tp->type_name;
prm.state = state;
prm.lastError = info ? info->status : PJ_SUCCESS;
+ pj_bzero(&prm.tlsInfo, sizeof(TlsInfo));
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+ if (!pj_ansi_stricmp(tp->type_name, "tls") && info->ext_info &&
+ (state == PJSIP_TP_STATE_CONNECTED ||
+ ((pjsip_tls_state_info*)info->ext_info)->
+ ssl_sock_info->verify_status != PJ_SUCCESS))
+ {
+ prm.tlsInfo.fromPj(*((pjsip_tls_state_info*)info->ext_info));
+ }
+#endif
ep.onTransportState(prm);
}
@@ -1694,6 +1782,11 @@ void Endpoint::transportClose(TransportId id) throw(Error)
PJSUA2_CHECK_EXPR( pjsua_transport_close(id, PJ_FALSE) );
}
+void Endpoint::transportShutdown(TransportHandle tp) throw(Error)
+{
+ PJSUA2_CHECK_EXPR( pjsip_transport_shutdown((pjsip_transport *)tp) );
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Call operations