Sun May 20 06:34:00 2012

Asterisk developer's documentation


sdp_crypto.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006 - 2007, Mikael Magnusson
00005  *
00006  * Mikael Magnusson <mikma@users.sourceforge.net>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file sdp_crypto.c
00020  *
00021  * \brief SDP Security descriptions
00022  *
00023  * Specified in RFC 4568
00024  *
00025  * \author Mikael Magnusson <mikma@users.sourceforge.net>
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356606 $")
00031 
00032 #include "asterisk/options.h"
00033 #include "asterisk/utils.h"
00034 #include "include/sdp_crypto.h"
00035 #include "include/srtp.h"
00036 
00037 #define SRTP_MASTER_LEN 30
00038 #define SRTP_MASTERKEY_LEN 16
00039 #define SRTP_MASTERSALT_LEN ((SRTP_MASTER_LEN) - (SRTP_MASTERKEY_LEN))
00040 #define SRTP_MASTER_LEN64 (((SRTP_MASTER_LEN) * 8 + 5) / 6 + 1)
00041 
00042 extern struct ast_srtp_res *res_srtp;
00043 extern struct ast_srtp_policy_res *res_srtp_policy;
00044 
00045 struct sdp_crypto {
00046    char *a_crypto;
00047    unsigned char local_key[SRTP_MASTER_LEN];
00048    char local_key64[SRTP_MASTER_LEN64];
00049 };
00050 
00051 static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound);
00052 
00053 static struct sdp_crypto *sdp_crypto_alloc(void)
00054 {
00055    struct sdp_crypto *crypto;
00056 
00057    return crypto = ast_calloc(1, sizeof(*crypto));
00058 }
00059 
00060 void sdp_crypto_destroy(struct sdp_crypto *crypto)
00061 {
00062    ast_free(crypto->a_crypto);
00063    crypto->a_crypto = NULL;
00064    ast_free(crypto);
00065 }
00066 
00067 struct sdp_crypto *sdp_crypto_setup(void)
00068 {
00069    struct sdp_crypto *p;
00070    int key_len;
00071    unsigned char remote_key[SRTP_MASTER_LEN];
00072 
00073    if (!ast_rtp_engine_srtp_is_registered()) {
00074       return NULL;
00075    }
00076 
00077    if (!(p = sdp_crypto_alloc())) {
00078       return NULL;
00079    }
00080 
00081    if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) {
00082       sdp_crypto_destroy(p);
00083       return NULL;
00084    }
00085 
00086    ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64));
00087 
00088    key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key));
00089 
00090    if (key_len != SRTP_MASTER_LEN) {
00091       ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN);
00092       ast_free(p);
00093       return NULL;
00094    }
00095 
00096    if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) {
00097       ast_log(LOG_ERROR, "base64 encode/decode bad key\n");
00098       ast_free(p);
00099       return NULL;
00100    }
00101 
00102    ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64));
00103 
00104    return p;
00105 }
00106 
00107 static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound)
00108 {
00109    const unsigned char *master_salt = NULL;
00110 
00111    if (!ast_rtp_engine_srtp_is_registered()) {
00112       return -1;
00113    }
00114 
00115    master_salt = master_key + SRTP_MASTERKEY_LEN;
00116    if (res_srtp_policy->set_master_key(policy, master_key, SRTP_MASTERKEY_LEN, master_salt, SRTP_MASTERSALT_LEN) < 0) {
00117       return -1;
00118    }
00119 
00120    if (res_srtp_policy->set_suite(policy, suite_val)) {
00121       ast_log(LOG_WARNING, "Could not set remote SRTP suite\n");
00122       return -1;
00123    }
00124 
00125    res_srtp_policy->set_ssrc(policy, ssrc, inbound);
00126 
00127    return 0;
00128 }
00129 
00130 static int sdp_crypto_activate(struct sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp)
00131 {
00132    struct ast_srtp_policy *local_policy = NULL;
00133    struct ast_srtp_policy *remote_policy = NULL;
00134    struct ast_rtp_instance_stats stats = {0,};
00135    int res = -1;
00136 
00137    if (!ast_rtp_engine_srtp_is_registered()) {
00138       return -1;
00139    }
00140 
00141    if (!p) {
00142       return -1;
00143    }
00144 
00145    if (!(local_policy = res_srtp_policy->alloc())) {
00146       return -1;
00147    }
00148 
00149    if (!(remote_policy = res_srtp_policy->alloc())) {
00150       goto err;
00151    }
00152 
00153    if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) {
00154       goto err;
00155    }
00156 
00157    if (set_crypto_policy(local_policy, suite_val, p->local_key, stats.local_ssrc, 0) < 0) {
00158       goto err;
00159    }
00160 
00161    if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0) {
00162       goto err;
00163    }
00164 
00165    /* Add the SRTP policies */
00166    if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy)) {
00167       ast_log(LOG_WARNING, "Could not set SRTP policies\n");
00168       goto err;
00169    }
00170 
00171    ast_debug(1 , "SRTP policy activated\n");
00172    res = 0;
00173 
00174 err:
00175    if (local_policy) {
00176       res_srtp_policy->destroy(local_policy);
00177    }
00178 
00179    if (remote_policy) {
00180       res_srtp_policy->destroy(remote_policy);
00181    }
00182 
00183    return res;
00184 }
00185 
00186 int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp)
00187 {
00188    char *str = NULL;
00189    char *tag = NULL;
00190    char *suite = NULL;
00191    char *key_params = NULL;
00192    char *key_param = NULL;
00193    char *session_params = NULL;
00194    char *key_salt = NULL;
00195    char *lifetime = NULL;
00196    int found = 0;
00197    int attr_len = strlen(attr);
00198    int key_len = 0;
00199    int suite_val = 0;
00200    unsigned char remote_key[SRTP_MASTER_LEN];
00201 
00202    if (!ast_rtp_engine_srtp_is_registered()) {
00203       return -1;
00204    }
00205 
00206    str = ast_strdupa(attr);
00207 
00208    strsep(&str, ":");
00209    tag = strsep(&str, " ");
00210    suite = strsep(&str, " ");
00211    key_params = strsep(&str, " ");
00212    session_params = strsep(&str, " ");
00213 
00214    if (!tag || !suite) {
00215       ast_log(LOG_WARNING, "Unrecognized a=%s", attr);
00216       return -1;
00217    }
00218 
00219    if (session_params) {
00220       ast_log(LOG_WARNING, "Unsupported crypto parameters: %s", session_params);
00221       return -1;
00222    }
00223 
00224    if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
00225       suite_val = AST_AES_CM_128_HMAC_SHA1_80;
00226       ast_set_flag(srtp, SRTP_CRYPTO_TAG_80);
00227    } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
00228       suite_val = AST_AES_CM_128_HMAC_SHA1_32;
00229       ast_set_flag(srtp, SRTP_CRYPTO_TAG_32);
00230    } else {
00231       ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite);
00232       return -1;
00233    }
00234 
00235    while ((key_param = strsep(&key_params, ";"))) {
00236       char *method = NULL;
00237       char *info = NULL;
00238 
00239       method = strsep(&key_param, ":");
00240       info = strsep(&key_param, ";");
00241 
00242       if (!strcmp(method, "inline")) {
00243          key_salt = strsep(&info, "|");
00244          lifetime = strsep(&info, "|");
00245 
00246          if (lifetime) {
00247             ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n", attr);
00248             continue;
00249          }
00250 
00251          found = 1;
00252          break;
00253       }
00254    }
00255 
00256    if (!found) {
00257       ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n");
00258       return -1;
00259    }
00260 
00261 
00262    if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) {
00263       ast_log(LOG_WARNING, "SRTP sdescriptions key %d != %d\n", key_len, SRTP_MASTER_LEN);
00264       return -1;
00265    }
00266 
00267    if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) {
00268       return -1;
00269    }
00270 
00271    if (!p->a_crypto) {
00272       if (!(p->a_crypto = ast_calloc(1, attr_len + 11))) {
00273          ast_log(LOG_ERROR, "Could not allocate memory for a_crypto\n");
00274          return -1;
00275       }
00276       snprintf(p->a_crypto, attr_len + 10, "a=crypto:%s %s inline:%s\r\n", tag, suite, p->local_key64);
00277    }
00278    return 0;
00279 }
00280 
00281 int sdp_crypto_offer(struct sdp_crypto *p, int taglen)
00282 {
00283    char crypto_buf[128];
00284 
00285    if (p->a_crypto) {
00286       ast_free(p->a_crypto);
00287    }
00288 
00289    if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 AES_CM_128_HMAC_SHA1_%i inline:%s\r\n",
00290          taglen, p->local_key64) < 1) {
00291       return -1;
00292    }
00293 
00294    if (!(p->a_crypto = ast_strdup(crypto_buf))) {
00295       return -1;
00296    }
00297 
00298    return 0;
00299 }
00300 
00301 const char *sdp_crypto_attrib(struct sdp_crypto *p)
00302 {
00303    return p->a_crypto;
00304 }

Generated on Sun May 20 06:34:00 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6