mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 03:50:31 +00:00
res_pjsip: Make transport cipher option accept a comma separated list of cipher names.
Improvements to the res_pjsip transport cipher option. * Made the cipher option accept a comma separated list of OpenSSL cipher names. Users of realtime will be glad if they have more than one name to list. * Added the CLI command 'pjsip list ciphers' so a user can know what OpenSSL names are available for the cipher option. * Updated the cipher option online XML documentation to specify what is expected for the value. * Updated pjsip.conf.sample to not indicate that ALL is acceptable since ALL does not imply a preference order for the ciphers and PJSIP does not simply pass the string to OpenSSL for interpretation. ASTERISK-24199 #close Reported by: Joshua Colp Review: https://reviewboard.asterisk.org/r/4018/ ........ Merged revisions 424393 from http://svn.asterisk.org/svn/asterisk/branches/12 ........ Merged revisions 424394 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@424395 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -148,7 +148,7 @@
|
||||
;bind=0.0.0.0
|
||||
;cert_file=/path/mycert.crt
|
||||
;priv_key_file=/path/mykey.key
|
||||
;cipher=ALL
|
||||
;cipher=ADH-AES256-SHA,ADH-AES128-SHA
|
||||
;method=tlsv1
|
||||
|
||||
|
||||
@@ -648,7 +648,7 @@
|
||||
;ca_list_file= ; File containing a list of certificates to read TLS ONLY
|
||||
; (default: "")
|
||||
;cert_file= ; Certificate file for endpoint TLS ONLY (default: "")
|
||||
;cipher= ; Preferred Cryptography Cipher TLS ONLY (default: "")
|
||||
;cipher= ; Preferred cryptography cipher names TLS ONLY (default: "")
|
||||
;domain= ; Domain the transport comes from (default: "")
|
||||
;external_media_address= ; External IP address to use in RTP handling
|
||||
; (default: "")
|
||||
|
@@ -653,9 +653,9 @@
|
||||
<description><para>
|
||||
This option only applies if <replaceable>media_encryption</replaceable> is
|
||||
set to <literal>dtls</literal>.
|
||||
</para><para>
|
||||
Many options for acceptable ciphers. See link for more:
|
||||
http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
|
||||
</para>
|
||||
<para>Many options for acceptable ciphers. See link for more:</para>
|
||||
<para>http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="dtls_ca_file">
|
||||
@@ -820,11 +820,17 @@
|
||||
<synopsis>Certificate file for endpoint (TLS ONLY)</synopsis>
|
||||
</configOption>
|
||||
<configOption name="cipher">
|
||||
<synopsis>Preferred Cryptography Cipher (TLS ONLY)</synopsis>
|
||||
<description><para>
|
||||
Many options for acceptable ciphers see link for more:
|
||||
http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
|
||||
</para></description>
|
||||
<synopsis>Preferred cryptography cipher names (TLS ONLY)</synopsis>
|
||||
<description>
|
||||
<para>Comma separated list of cipher names or numeric equivalents.
|
||||
Numeric quivalents can be either decimal or hexadecimal (0xX).
|
||||
</para>
|
||||
<para>There are many cipher names. Use the CLI command
|
||||
<literal>pjsip list ciphers</literal> to see a list of cipher
|
||||
names available for your installation. See link for more:</para>
|
||||
<para>http://www.openssl.org/docs/apps/ciphers.html#CIPHER_SUITE_NAMES
|
||||
</para>
|
||||
</description>
|
||||
</configOption>
|
||||
<configOption name="domain">
|
||||
<synopsis>Domain the transport comes from</synopsis>
|
||||
|
@@ -389,17 +389,19 @@ static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf)
|
||||
/*! \brief Helper function which turns a cipher name into an identifier */
|
||||
static pj_ssl_cipher cipher_name_to_id(const char *name)
|
||||
{
|
||||
pj_ssl_cipher ciphers[100], id = 0;
|
||||
pj_ssl_cipher ciphers[100];
|
||||
pj_ssl_cipher id = 0;
|
||||
unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
|
||||
int pos;
|
||||
const char *pos_name;
|
||||
|
||||
if (pj_ssl_cipher_get_availables(ciphers, &cipher_num)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pos = 0; pos < cipher_num; ++pos) {
|
||||
if (!pj_ssl_cipher_name(ciphers[pos]) ||
|
||||
strcmp(pj_ssl_cipher_name(ciphers[pos]), name)) {
|
||||
pos_name = pj_ssl_cipher_name(ciphers[pos]);
|
||||
if (!pos_name || strcmp(pos_name, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -410,60 +412,130 @@ static pj_ssl_cipher cipher_name_to_id(const char *name)
|
||||
return id;
|
||||
}
|
||||
|
||||
/*! \brief Custom handler for TLS cipher setting */
|
||||
static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Add a new cipher to the transport's cipher list array.
|
||||
*
|
||||
* \param transport Which transport to add the cipher to.
|
||||
* \param name Cipher identifier name.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
static int transport_cipher_add(struct ast_sip_transport *transport, const char *name)
|
||||
{
|
||||
struct ast_sip_transport *transport = obj;
|
||||
pj_ssl_cipher cipher;
|
||||
int idx;
|
||||
|
||||
if (ast_strlen_zero(var->value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (transport->tls.ciphers_num == (SIP_TLS_MAX_CIPHERS - 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cipher = cipher_name_to_id(var->value);
|
||||
|
||||
cipher = cipher_name_to_id(name);
|
||||
if (!cipher) {
|
||||
/* TODO: Check this over/tweak - it's taken from pjsua for now */
|
||||
if (!strnicmp(var->value, "0x", 2)) {
|
||||
pj_str_t cipher_st = pj_str((char*)var->value + 2);
|
||||
if (!strnicmp(name, "0x", 2)) {
|
||||
pj_str_t cipher_st = pj_str((char *) name + 2);
|
||||
cipher = pj_strtoul2(&cipher_st, NULL, 16);
|
||||
} else {
|
||||
cipher = atoi(var->value);
|
||||
cipher = atoi(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (pj_ssl_cipher_is_supported(cipher)) {
|
||||
for (idx = transport->tls.ciphers_num; idx--;) {
|
||||
if (transport->ciphers[idx] == cipher) {
|
||||
/* The cipher is already in the list. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
transport->ciphers[transport->tls.ciphers_num++] = cipher;
|
||||
return 0;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", var->value);
|
||||
ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
|
||||
/*! \brief Custom handler for TLS cipher setting */
|
||||
static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
{
|
||||
RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
|
||||
const struct ast_sip_transport *transport = obj;
|
||||
int i;
|
||||
struct ast_sip_transport *transport = obj;
|
||||
char *parse;
|
||||
char *name;
|
||||
int res = 0;
|
||||
|
||||
parse = ast_strdupa(S_OR(var->value, ""));
|
||||
while ((name = strsep(&parse, ","))) {
|
||||
name = ast_strip(name);
|
||||
if (ast_strlen_zero(name)) {
|
||||
continue;
|
||||
}
|
||||
if (ARRAY_LEN(transport->ciphers) <= transport->tls.ciphers_num) {
|
||||
ast_log(LOG_ERROR, "Too many ciphers specified\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
res |= transport_cipher_add(transport, name);
|
||||
}
|
||||
return res ? -1 : 0;
|
||||
}
|
||||
|
||||
static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int cipher_num)
|
||||
{
|
||||
struct ast_str *str;
|
||||
int idx;
|
||||
|
||||
str = ast_str_create(128);
|
||||
if (!str) {
|
||||
return -1;
|
||||
*buf = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < transport->tls.ciphers_num; ++i) {
|
||||
ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(transport->ciphers[i]));
|
||||
if (i < transport->tls.ciphers_num - 1) {
|
||||
ast_str_append(&str, 0, ",");
|
||||
for (idx = 0; idx < cipher_num; ++idx) {
|
||||
ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(ciphers[idx]));
|
||||
if (idx < cipher_num - 1) {
|
||||
ast_str_append(&str, 0, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
*buf = ast_strdup(ast_str_buffer(str));
|
||||
return 0;
|
||||
ast_free(str);
|
||||
}
|
||||
|
||||
static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
|
||||
{
|
||||
const struct ast_sip_transport *transport = obj;
|
||||
|
||||
cipher_to_str(buf, transport->ciphers, transport->tls.ciphers_num);
|
||||
return *buf ? 0 : -1;
|
||||
}
|
||||
|
||||
static char *handle_pjsip_list_ciphers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
pj_ssl_cipher ciphers[100];
|
||||
unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
|
||||
char *buf;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "pjsip list ciphers";
|
||||
e->usage = "Usage: pjsip list ciphers\n"
|
||||
" List available OpenSSL cipher names.\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pj_ssl_cipher_get_availables(ciphers, &cipher_num) || !cipher_num) {
|
||||
buf = NULL;
|
||||
} else {
|
||||
cipher_to_str(&buf, ciphers, cipher_num);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(buf)) {
|
||||
ast_cli(a->fd, "Available ciphers: '%s'\n", buf);
|
||||
} else {
|
||||
ast_cli(a->fd, "No available ciphers\n");
|
||||
}
|
||||
ast_free(buf);
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
/*! \brief Custom handler for localnet setting */
|
||||
@@ -638,6 +710,7 @@ static int cli_print_body(void *obj, void *arg, int flags)
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_commands[] = {
|
||||
AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
|
||||
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
|
||||
.command = "pjsip list transports",
|
||||
.usage = "Usage: pjsip list transports\n"
|
||||
|
Reference in New Issue
Block a user