summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjlib/include/pj/ssl_sock.h24
-rw-r--r--pjlib/src/pj/ssl_sock_common.c100
-rw-r--r--pjlib/src/pj/ssl_sock_ossl.c57
-rw-r--r--pjlib/src/pj/ssl_sock_symbian.cpp198
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c74
-rw-r--r--pjsip/include/pjsip/sip_transport_tls.h24
-rw-r--r--pjsip/src/pjsip/sip_transport_tls.c5
7 files changed, 334 insertions, 148 deletions
diff --git a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h
index faf82f5e..0e8fb4a4 100644
--- a/pjlib/include/pj/ssl_sock.h
+++ b/pjlib/include/pj/ssl_sock.h
@@ -332,16 +332,38 @@ PJ_DECL(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
/**
+ * Check if the specified cipher is supported by SSL/TLS backend.
+ *
+ * @param cipher The cipher.
+ *
+ * @return PJ_TRUE when supported.
+ */
+PJ_DECL(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher);
+
+
+/**
* Get cipher name string.
*
* @param cipher The cipher.
*
- * @return The cipher name or NULL if cipher is not recognized.
+ * @return The cipher name or NULL if cipher is not recognized/
+ * supported.
*/
PJ_DECL(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher);
/**
+ * Get cipher ID from cipher name string.
+ *
+ * @param cipher_name The cipher name string.
+ *
+ * @return The cipher ID or PJ_TLS_UNKNOWN_CIPHER if the cipher
+ * name string is not recognized/supported.
+ */
+PJ_DECL(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name);
+
+
+/**
* This structure contains the callbacks to be called by the secure socket.
*/
typedef struct pj_ssl_sock_cb
diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c
index c70a7af1..67a8d63c 100644
--- a/pjlib/src/pj/ssl_sock_common.c
+++ b/pjlib/src/pj/ssl_sock_common.c
@@ -21,89 +21,6 @@
#include <pj/errno.h>
#include <pj/string.h>
-/* Cipher name structure */
-typedef struct cipher_name_t {
- pj_ssl_cipher cipher;
- const char *name;
-} cipher_name_t;
-
-/* Cipher name constants */
-static cipher_name_t cipher_names[] =
-{
- {PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
-
- /* TLS/SSLv3 */
- {PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
- {PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
- {PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
- {PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
- {PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
- {PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
- {PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
- {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
- {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
- {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
- {PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
- {PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
- {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
- {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
- {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
- {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
-
- /* TLS (deprecated) */
- {PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
- {PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
- {PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
- {PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
- {PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
- {PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
- {PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
- {PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
- {PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
- {PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
- {PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
-
- /* SSLv3 */
- {PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
- {PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
- {PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
-
- /* SSLv2 */
- {PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
- {PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
- {PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
- {PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
- {PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
- {PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
- {PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
-};
-
-
/*
* Initialize the SSL socket configuration with the default values.
*/
@@ -129,23 +46,6 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
}
-/* Get cipher name string */
-PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
-{
- unsigned i, n;
-
- n = PJ_ARRAY_SIZE(cipher_names);
- for (i = 0; i < n; ++i) {
- if (cipher == cipher_names[i].cipher)
- return cipher_names[i].name;
- }
-
- return NULL;
-}
-
-
-
-
PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings(
pj_uint32_t verify_status,
const char *error_strings[],
diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
index 6ce44ad1..559b5134 100644
--- a/pjlib/src/pj/ssl_sock_ossl.c
+++ b/pjlib/src/pj/ssl_sock_ossl.c
@@ -39,6 +39,9 @@
/* Workaround for ticket #985 */
#define DELAYED_CLOSE_TIMEOUT 200
+/* Maximum ciphers */
+#define MAX_CIPHERS 100
+
/*
* Include OpenSSL headers
*/
@@ -269,8 +272,11 @@ static pj_str_t ssl_strerror(pj_status_t status,
static int openssl_init_count;
/* OpenSSL available ciphers */
-static pj_ssl_cipher openssl_ciphers[100];
static unsigned openssl_cipher_num;
+static struct openssl_ciphers_t {
+ pj_ssl_cipher id;
+ const char *name;
+} openssl_ciphers[MAX_CIPHERS];
/* OpenSSL application data index */
static int sslsock_idx;
@@ -329,9 +335,9 @@ static pj_status_t init_openssl(void)
for (i = 0; i < n; ++i) {
SSL_CIPHER *c;
c = sk_SSL_CIPHER_value(sk_cipher,i);
- openssl_ciphers[i] = (pj_ssl_cipher)
- (pj_uint32_t)c->id & 0x00FFFFFF;
- //printf("%3u: %08x=%s\n", i+1, c->id, SSL_CIPHER_get_name(c));
+ openssl_ciphers[i].id = (pj_ssl_cipher)
+ (pj_uint32_t)c->id & 0x00FFFFFF;
+ openssl_ciphers[i].name = SSL_CIPHER_get_name(c);
}
SSL_free(ssl);
@@ -1705,18 +1711,57 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
shutdown_openssl();
}
- if (openssl_cipher_num == 0)
+ if (openssl_cipher_num == 0) {
+ *cipher_num = 0;
return PJ_ENOTFOUND;
+ }
*cipher_num = PJ_MIN(*cipher_num, openssl_cipher_num);
for (i = 0; i < *cipher_num; ++i)
- ciphers[i] = openssl_ciphers[i];
+ ciphers[i] = openssl_ciphers[i].id;
return PJ_SUCCESS;
}
+/* Get cipher name string */
+PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (openssl_cipher_num == 0) {
+ init_openssl();
+ shutdown_openssl();
+ }
+
+ for (i = 0; i < openssl_cipher_num; ++i) {
+ if (cipher == openssl_ciphers[i].id)
+ return openssl_ciphers[i].name;
+ }
+
+ return NULL;
+}
+
+/* Check if the specified cipher is supported by SSL/TLS backend. */
+PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (openssl_cipher_num == 0) {
+ init_openssl();
+ shutdown_openssl();
+ }
+
+ for (i = 0; i < openssl_cipher_num; ++i) {
+ if (cipher == openssl_ciphers[i].id)
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+
/*
* Create SSL socket instance.
*/
diff --git a/pjlib/src/pj/ssl_sock_symbian.cpp b/pjlib/src/pj/ssl_sock_symbian.cpp
index 95c10077..47288fae 100644
--- a/pjlib/src/pj/ssl_sock_symbian.cpp
+++ b/pjlib/src/pj/ssl_sock_symbian.cpp
@@ -32,6 +32,104 @@
#define THIS_FILE "ssl_sock_symbian.cpp"
+
+/* Cipher name structure */
+typedef struct cipher_name_t {
+ pj_ssl_cipher cipher;
+ const char *name;
+} cipher_name_t;
+
+/* Cipher name constants */
+static cipher_name_t cipher_names[] =
+{
+ {PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
+
+ /* TLS/SSLv3 */
+ {PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
+ {PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
+ {PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
+ {PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
+ {PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
+ {PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
+ {PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
+
+ /* TLS (deprecated) */
+ {PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
+ {PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
+ {PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
+ {PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
+ {PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
+
+ /* SSLv3 */
+ {PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
+ {PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
+ {PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
+
+ /* SSLv2 */
+ {PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
+ {PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
+ {PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
+ {PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
+ {PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
+ {PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
+ {PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
+};
+
+
+/* Get cipher name string */
+static const char* get_cipher_name(pj_ssl_cipher cipher)
+{
+ unsigned i, n;
+
+ n = PJ_ARRAY_SIZE(cipher_names);
+ for (i = 0; i < n; ++i) {
+ if (cipher == cipher_names[i].cipher)
+ return cipher_names[i].name;
+ }
+
+ return "CIPHER_UNKNOWN";
+}
+
typedef void (*CPjSSLSocket_cb)(int err, void *key);
class CPjSSLSocketReader : public CActive
@@ -115,7 +213,8 @@ public:
int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
const TInetAddr &rem_addr,
- const TDesC8 &servername = TPtrC8(NULL,0));
+ const TDesC8 &servername = TPtrC8(NULL,0),
+ const TDesC8 &ciphers = TPtrC8(NULL,0));
int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
int SendSync(const TDesC8 &aDesc, TUint flags);
@@ -146,6 +245,7 @@ private:
TBuf<32> ssl_proto_;
TInetAddr rem_addr_;
TPtrC8 servername_;
+ TPtrC8 ciphers_;
TInetAddr local_addr_;
TSockXfrLength sent_len_;
@@ -186,7 +286,8 @@ private:
int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
const TInetAddr &local_addr,
const TInetAddr &rem_addr,
- const TDesC8 &servername)
+ const TDesC8 &servername,
+ const TDesC8 &ciphers)
{
pj_status_t status;
@@ -213,7 +314,11 @@ int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
cb_ = cb;
key_ = key;
rem_addr_ = rem_addr;
+
+ /* Note: the following members only keep the pointer, not the data */
servername_.Set(servername);
+ ciphers_.Set(ciphers);
+
rSock.Connect(rem_addr_, iStatus);
SetActive();
state_ = SSL_STATE_CONNECTING;
@@ -318,6 +423,8 @@ void CPjSSLSocket::RunL()
if (servername_.Length() > 0)
securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
servername_);
+ if (ciphers_.Length() > 0)
+ securesock_->SetAvailableCipherSuites(ciphers_);
// FlushSessionCache() seems to also fire signals to all
// completed AOs (something like CActiveScheduler::RunIfReady())
@@ -441,9 +548,8 @@ struct pj_ssl_sock_t
pj_ssl_sock_proto proto;
pj_time_val timeout;
- unsigned ciphers_num;
- pj_ssl_cipher *ciphers;
pj_str_t servername;
+ pj_str_t ciphers;
pj_ssl_cert_info remote_cert_info;
};
@@ -579,15 +685,20 @@ static void update_certs_info(pj_ssl_sock_t *ssock)
}
+/* Available ciphers */
+static unsigned ciphers_num_ = 0;
+static struct ciphers_t
+{
+ pj_ssl_cipher id;
+ const char *name;
+} ciphers_[64];
+
/*
* Get cipher list supported by SSL/TLS backend.
*/
PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
unsigned *cipher_num)
{
- /* Available ciphers */
- static pj_ssl_cipher ciphers_[64];
- static unsigned ciphers_num_ = 0;
unsigned i;
PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
@@ -605,25 +716,69 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
ciphers_num_ = ciphers_buf.Length() / 2;
if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
- for (i = 0; i < ciphers_num_; ++i)
- ciphers_[i] = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
- ciphers_buf[i*2+1]);
+ for (i = 0; i < ciphers_num_; ++i) {
+ ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
+ ciphers_buf[i*2+1]);
+ ciphers_[i].name = get_cipher_name(ciphers_[i].id);
+ }
}
delete secure_sock;
}
if (ciphers_num_ == 0) {
+ *cipher_num = 0;
return PJ_ENOTFOUND;
}
*cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
for (i = 0; i < *cipher_num; ++i)
- ciphers[i] = ciphers_[i];
+ ciphers[i] = ciphers_[i].id;
return PJ_SUCCESS;
}
+
+/* Get cipher name string */
+PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (ciphers_num_ == 0) {
+ pj_ssl_cipher c[1];
+ i = 0;
+ pj_ssl_cipher_get_availables(c, &i);
+ }
+
+ for (i = 0; i < ciphers_num_; ++i) {
+ if (cipher == ciphers_[i].id)
+ return ciphers_[i].name;
+ }
+
+ return NULL;
+}
+
+
+/* Check if the specified cipher is supported by SSL/TLS backend. */
+PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (ciphers_num_ == 0) {
+ pj_ssl_cipher c[1];
+ i = 0;
+ pj_ssl_cipher_get_availables(c, &i);
+ }
+
+ for (i = 0; i < ciphers_num_; ++i) {
+ if (cipher == ciphers_[i].id)
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+
/*
* Create SSL socket instance.
*/
@@ -652,14 +807,15 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
ssock->cb = param->cb;
ssock->user_data = param->user_data;
ssock->timeout = param->timeout;
- ssock->ciphers_num = param->ciphers_num;
if (param->ciphers_num > 0) {
- unsigned i;
- ssock->ciphers = (pj_ssl_cipher*)
- pj_pool_calloc(pool, param->ciphers_num,
- sizeof(pj_ssl_cipher));
- for (i = 0; i < param->ciphers_num; ++i)
- ssock->ciphers[i] = param->ciphers[i];
+ /* Cipher list in Symbian is represented as array of two-octets. */
+ ssock->ciphers.slen = param->ciphers_num*2;
+ ssock->ciphers.ptr = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
+ pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
+ for (unsigned i = 0; i < param->ciphers_num; ++i) {
+ *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
+ *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
+ }
}
pj_strdup_with_null(pool, &ssock->servername, &param->server_name);
@@ -1246,9 +1402,13 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
TPtrC8 servername_((TUint8*)ssock->servername.ptr,
ssock->servername.slen);
+ /* Convert cipher list to Symbian descriptor */
+ TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
+ ssock->ciphers.slen);
+
/* Try to connect */
status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
- servername_);
+ servername_, ciphers_);
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
delete sock;
return status;
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 81e6d57f..0c3d3eb6 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -251,6 +251,8 @@ static void usage(void)
puts (" May be specified multiple times");
puts (" --stun-srv=FORMAT Set STUN server host or domain. This option may be");
puts (" specified more than once. FORMAT is hostdom[:PORT]");
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
puts ("");
puts ("TLS Options:");
puts (" --use-tls Enable TLS transport (default=no)");
@@ -262,6 +264,9 @@ static void usage(void)
puts (" --tls-verify-client Verify client's certificate (default=no)");
puts (" --tls-neg-timeout Specify TLS negotiation timeout (default=no)");
puts (" --tls-srv-name Specify TLS server name for multihosting server");
+ puts (" --tls-cipher Specify prefered TLS cipher (optional).");
+ puts (" May be specified multiple times");
+#endif
puts ("");
puts ("Media Options:");
@@ -529,7 +534,7 @@ static pj_status_t parse_args(int argc, char *argv[],
OPT_NOREFERSUB, OPT_ACCEPT_REDIRECT,
OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE,
OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT,
- OPT_TLS_NEG_TIMEOUT, OPT_TLS_SRV_NAME,
+ OPT_TLS_NEG_TIMEOUT, OPT_TLS_SRV_NAME, OPT_TLS_CIPHER,
OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,
OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_JB_MAX_SIZE,
OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS,
@@ -628,6 +633,7 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "max-calls", 1, 0, OPT_MAX_CALLS},
{ "duration", 1, 0, OPT_DURATION},
{ "thread-cnt", 1, 0, OPT_THREAD_CNT},
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
{ "use-tls", 0, 0, OPT_USE_TLS},
{ "tls-ca-file",1, 0, OPT_TLS_CA_FILE},
{ "tls-cert-file",1,0, OPT_TLS_CERT_FILE},
@@ -637,6 +643,8 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "tls-verify-client", 0, 0, OPT_TLS_VERIFY_CLIENT},
{ "tls-neg-timeout", 1, 0, OPT_TLS_NEG_TIMEOUT},
{ "tls-srv-name", 1, 0, OPT_TLS_SRV_NAME},
+ { "tls-cipher", 1, 0, OPT_TLS_CIPHER},
+#endif
{ "capture-dev", 1, 0, OPT_CAPTURE_DEV},
{ "playback-dev", 1, 0, OPT_PLAYBACK_DEV},
{ "capture-lat", 1, 0, OPT_CAPTURE_LAT},
@@ -1303,28 +1311,17 @@ static pj_status_t parse_args(int argc, char *argv[],
}
break;
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
case OPT_USE_TLS:
cfg->use_tls = PJ_TRUE;
-#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
- PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
- return -1;
-#endif
break;
case OPT_TLS_CA_FILE:
cfg->udp_cfg.tls_setting.ca_list_file = pj_str(pj_optarg);
-#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
- PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
- return -1;
-#endif
break;
case OPT_TLS_CERT_FILE:
cfg->udp_cfg.tls_setting.cert_file = pj_str(pj_optarg);
-#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
- PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
- return -1;
-#endif
break;
case OPT_TLS_PRIV_FILE:
@@ -1333,10 +1330,6 @@ static pj_status_t parse_args(int argc, char *argv[],
case OPT_TLS_PASSWORD:
cfg->udp_cfg.tls_setting.password = pj_str(pj_optarg);
-#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
- PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
- return -1;
-#endif
break;
case OPT_TLS_VERIFY_SERVER:
@@ -1355,6 +1348,39 @@ static pj_status_t parse_args(int argc, char *argv[],
case OPT_TLS_SRV_NAME:
cfg->udp_cfg.tls_setting.server_name = pj_str(pj_optarg);
break;
+ case OPT_TLS_CIPHER:
+ {
+ pj_ssl_cipher cipher;
+
+ if (pj_ansi_strnicmp(pj_optarg, "0x", 2) == 0) {
+ pj_str_t cipher_st = pj_str(pj_optarg + 2);
+ cipher = pj_strtoul2(&cipher_st, NULL, 16);
+ } else {
+ cipher = atoi(pj_optarg);
+ }
+
+ if (pj_ssl_cipher_is_supported(cipher)) {
+ static pj_ssl_cipher tls_ciphers[128];
+
+ tls_ciphers[cfg->udp_cfg.tls_setting.ciphers_num++] = cipher;
+ cfg->udp_cfg.tls_setting.ciphers = tls_ciphers;
+ } else {
+ pj_ssl_cipher ciphers[128];
+ unsigned j, ciphers_cnt;
+
+ ciphers_cnt = PJ_ARRAY_SIZE(ciphers);
+ pj_ssl_cipher_get_availables(ciphers, &ciphers_cnt);
+
+ PJ_LOG(1,(THIS_FILE, "Cipher \"%s\" is not supported by "
+ "TLS/SSL backend.", pj_optarg));
+ printf("Available TLS/SSL ciphers (%d):\n", ciphers_cnt);
+ for (j=0; j<ciphers_cnt; ++j)
+ printf("- 0x%06X: %s\n", ciphers[j], pj_ssl_cipher_name(ciphers[j]));
+ return -1;
+ }
+ }
+ break;
+#endif /* PJSIP_HAS_TLS_TRANSPORT */
case OPT_CAPTURE_DEV:
cfg->capture_dev = atoi(pj_optarg);
@@ -1773,6 +1799,7 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
}
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
/* TLS */
if (config->use_tls)
pj_strcat2(&cfg, "--use-tls\n");
@@ -1821,6 +1848,14 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
}
+ for (i=0; i<config->udp_cfg.tls_setting.ciphers_num; ++i) {
+ pj_ansi_sprintf(line, "--tls-cipher 0x%06X # %s\n",
+ config->udp_cfg.tls_setting.ciphers[i],
+ pj_ssl_cipher_name(config->udp_cfg.tls_setting.ciphers[i]));
+ pj_strcat2(&cfg, line);
+ }
+#endif
+
pj_strcat2(&cfg, "\n#\n# Media settings:\n#\n");
/* SRTP */
@@ -3006,6 +3041,11 @@ static void on_transport_state(pjsip_transport *tp,
const char *verif_msgs[32];
unsigned verif_msg_cnt;
+ /* Dump server TLS cipher */
+ PJ_LOG(4,(THIS_FILE, "TLS cipher used: 0x%06X/%s",
+ ssl_sock_info->cipher,
+ pj_ssl_cipher_name(ssl_sock_info->cipher) ));
+
/* Dump server TLS certificate */
pj_ssl_cert_info_dump(ssl_sock_info->remote_cert_info, " ",
buf, sizeof(buf));
diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h
index f9426412..241b063b 100644
--- a/pjsip/include/pjsip/sip_transport_tls.h
+++ b/pjsip/include/pjsip/sip_transport_tls.h
@@ -26,6 +26,7 @@
*/
#include <pjsip/sip_transport.h>
+#include <pj/pool.h>
#include <pj/ssl_sock.h>
#include <pj/string.h>
#include <pj/sock_qos.h>
@@ -106,10 +107,19 @@ typedef struct pjsip_tls_setting
int method;
/**
- * TLS cipher list string in OpenSSL format. If empty, then default
- * cipher list of the backend will be used.
+ * Number of ciphers contained in the specified cipher preference.
+ * If this is set to zero, then default cipher list of the backend
+ * will be used.
+ *
+ * Default: 0 (zero).
+ */
+ unsigned ciphers_num;
+
+ /**
+ * Ciphers and order preference. The #pj_ssl_cipher_get_availables()
+ * can be used to check the available ciphers supported by backend.
*/
- pj_str_t ciphers;
+ pj_ssl_cipher *ciphers;
/**
* Optionally specify the server name instance to be contacted when
@@ -246,7 +256,13 @@ PJ_INLINE(void) pjsip_tls_setting_copy(pj_pool_t *pool,
pj_strdup_with_null(pool, &dst->cert_file, &src->cert_file);
pj_strdup_with_null(pool, &dst->privkey_file, &src->privkey_file);
pj_strdup_with_null(pool, &dst->password, &src->password);
- pj_strdup_with_null(pool, &dst->ciphers, &src->ciphers);
+ if (src->ciphers_num) {
+ unsigned i;
+ dst->ciphers = (pj_ssl_cipher*) pj_pool_calloc(pool, src->ciphers_num,
+ sizeof(pj_ssl_cipher));
+ for (i=0; i<src->ciphers_num; ++i)
+ dst->ciphers[i] = src->ciphers[i];
+ }
}
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index face6b88..bae3ffd1 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -293,6 +293,8 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
+ ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
+ ssock_param.ciphers = listener->tls_setting.ciphers;
ssock_param.qos_type = listener->tls_setting.qos_type;
ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
@@ -862,7 +864,6 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
ssock_param.cb.on_data_sent = &on_data_sent;
ssock_param.async_cnt = 1;
ssock_param.ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
- PJ_TODO(synchronize_tls_cipher_type_with_ssl_sock_cipher_type);
ssock_param.server_name = remote_name;
ssock_param.timeout = listener->tls_setting.timeout;
ssock_param.user_data = NULL; /* pending, must be set later */
@@ -872,6 +873,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
+ ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
+ ssock_param.ciphers = listener->tls_setting.ciphers;
ssock_param.qos_type = listener->tls_setting.qos_type;
ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,