static int base64_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len) { if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Syntax: %s(<data>) - missing argument!\n", cmd); return -1; } if (cmd[7] == 'E') { if (buf) { ast_base64encode(buf, (unsigned char *) data, strlen(data), len); } else { if (len >= 0) { ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 4 / 3 + 2); } ast_base64encode(ast_str_buffer(*str) + ast_str_strlen(*str), (unsigned char *) data, strlen(data), ast_str_size(*str) - ast_str_strlen(*str)); ast_str_update(*str); } } else { int decoded_len; if (buf) { decoded_len = ast_base64decode((unsigned char *) buf, data, len); /* add a terminating null at the end of buf, or at the * end of our decoded string, which ever is less */ buf[decoded_len <= (len - 1) ? decoded_len : len - 1] = '\0'; } else { if (len >= 0) { ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 3 / 4 + 2); } decoded_len = ast_base64decode((unsigned char *) ast_str_buffer(*str) + ast_str_strlen(*str), data, ast_str_size(*str) - ast_str_strlen(*str)); if (len) /* add a terminating null at the end of our * buffer, or at the end of our decoded string, * which ever is less */ ast_str_buffer(*str)[decoded_len <= (len - 1) ? decoded_len : len - 1] = '\0'; else /* space for the null is allocated above */ ast_str_buffer(*str)[decoded_len] = '\0'; ast_str_update(*str); } } return 0; }
static int base64_decode(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) { if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Syntax: BASE64_DECODE(<base_64 string>) - missing argument!\n"); return -1; } ast_base64decode((unsigned char *) buf, data, len); return 0; }
static int __ast_check_signature(struct ast_key *key, const char *msg, const char *sig) { unsigned char dsig[128]; int res; /* Decode signature */ res = ast_base64decode(dsig, sig, sizeof(dsig)); if (res != sizeof(dsig)) { ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res); return -1; } res = ast_check_signature_bin(key, msg, strlen(msg), dsig); return res; }
static int base64_decode(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { int decoded_len; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Syntax: BASE64_DECODE(<base_64 string>) - missing argument!\n"); return -1; } decoded_len = ast_base64decode((unsigned char *) buf, data, len); if (decoded_len <= (len - 1)) { /* if not truncated, */ buf[decoded_len] = '\0'; } else { buf[len - 1] = '\0'; } return 0; }
struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) { struct ast_sdp_crypto *p; int key_len; unsigned char remote_key[SRTP_MASTER_LEN]; if (!ast_rtp_engine_srtp_is_registered()) { return NULL; } if (!(p = ast_calloc(1, sizeof(*p)))) { return NULL; } p->tag = 1; if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) { ast_sdp_crypto_destroy(p); return NULL; } ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64)); key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); if (key_len != SRTP_MASTER_LEN) { ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN); ast_sdp_crypto_destroy(p); return NULL; } if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) { ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); ast_sdp_crypto_destroy(p); return NULL; } ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); return p; }
int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr) { char *str = NULL; char *tag = NULL; char *suite = NULL; char *key_params = NULL; char *key_param = NULL; char *session_params = NULL; char *key_salt = NULL; /* The actual master key and key salt */ char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ char *mki = NULL; /* Master Key Index */ int found = 0; int key_len = 0; int suite_val = 0; unsigned char remote_key[SRTP_MASTER_LEN]; int taglen = 0; double sdes_lifetime; struct ast_sdp_crypto *crypto = srtp->crypto; if (!ast_rtp_engine_srtp_is_registered()) { return -1; } str = ast_strdupa(attr); tag = strsep(&str, " "); suite = strsep(&str, " "); key_params = strsep(&str, " "); session_params = strsep(&str, " "); if (!tag || !suite) { ast_log(LOG_WARNING, "Unrecognized crypto attribute a=%s\n", attr); return -1; } /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ if (sscanf(tag, "%30d", &crypto->tag) != 1 || crypto->tag <= 0 || crypto->tag > 999999999) { ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); return -1; } if (!ast_strlen_zero(session_params)) { ast_log(LOG_WARNING, "Unsupported crypto parameters: %s\n", session_params); return -1; } if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { suite_val = AST_AES_CM_128_HMAC_SHA1_80; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); taglen = 80; } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { suite_val = AST_AES_CM_128_HMAC_SHA1_32; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); taglen = 32; } else { ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite); return -1; } while ((key_param = strsep(&key_params, ";"))) { unsigned int n_lifetime; char *method = NULL; char *info = NULL; method = strsep(&key_param, ":"); info = strsep(&key_param, ";"); sdes_lifetime = 0; if (strcmp(method, "inline")) { continue; } key_salt = strsep(&info, "|"); /* The next parameter can be either lifetime or MKI */ lifetime = strsep(&info, "|"); if (!lifetime) { found = 1; break; } mki = strchr(lifetime, ':'); if (mki) { mki = lifetime; lifetime = NULL; } else { mki = strsep(&info, "|"); } if (mki && *mki != '1') { ast_log(LOG_NOTICE, "Crypto MKI handling is not supported: ignoring attribute %s\n", attr); continue; } if (lifetime) { if (!strncmp(lifetime, "2^", 2)) { char *lifetime_val = lifetime + 2; /* Exponential lifetime */ if (sscanf(lifetime_val, "%30u", &n_lifetime) != 1) { ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); continue; } if (n_lifetime > 48) { /* Yeah... that's a bit big. */ ast_log(LOG_NOTICE, "Crypto lifetime exponent of '%u' is a bit large; using 48\n", n_lifetime); n_lifetime = 48; } sdes_lifetime = pow(2, n_lifetime); } else { /* Decimal lifetime */ if (sscanf(lifetime, "%30u", &n_lifetime) != 1) { ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); continue; } sdes_lifetime = n_lifetime; } /* Accept anything above 10 hours. Less than 10; reject. */ if (sdes_lifetime < 1800000) { ast_log(LOG_NOTICE, "Rejecting crypto attribute '%s': lifetime '%f' too short\n", attr, sdes_lifetime); continue; } } ast_debug(2, "Crypto attribute '%s' accepted with lifetime '%f', MKI '%s'\n", attr, sdes_lifetime, mki ? mki : "-"); found = 1; break; } if (!found) { ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable: '%s'\n", attr); return -1; } key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); if (key_len != SRTP_MASTER_LEN) { ast_log(LOG_WARNING, "SRTP descriptions key length '%d' != master length '%d'\n", key_len, SRTP_MASTER_LEN); return -1; } if (!memcmp(crypto->remote_key, remote_key, sizeof(crypto->remote_key))) { ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; } memcpy(crypto->remote_key, remote_key, sizeof(crypto->remote_key)); if (crypto_activate(crypto, suite_val, remote_key, rtp) < 0) { return -1; } /* Finally, rebuild the crypto line */ if (ast_sdp_crypto_build_offer(crypto, taglen)) { return -1; } ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; }
int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp) { char *str = NULL; char *tag = NULL; char *suite = NULL; char *key_params = NULL; char *key_param = NULL; char *session_params = NULL; char *key_salt = NULL; char *lifetime = NULL; int found = 0; int key_len = 0; int suite_val = 0; unsigned char remote_key[SRTP_MASTER_LEN]; int taglen = 0; if (!ast_rtp_engine_srtp_is_registered()) { return -1; } str = ast_strdupa(attr); strsep(&str, ":"); tag = strsep(&str, " "); suite = strsep(&str, " "); key_params = strsep(&str, " "); session_params = strsep(&str, " "); if (!tag || !suite) { ast_log(LOG_WARNING, "Unrecognized a=%s", attr); return -1; } if (!ast_strlen_zero(session_params)) { ast_log(LOG_WARNING, "Unsupported crypto parameters: %s", session_params); return -1; } if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { suite_val = AST_AES_CM_128_HMAC_SHA1_80; ast_set_flag(srtp, SRTP_CRYPTO_TAG_80); taglen = 80; } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { suite_val = AST_AES_CM_128_HMAC_SHA1_32; ast_set_flag(srtp, SRTP_CRYPTO_TAG_32); taglen = 32; } else { ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite); return -1; } while ((key_param = strsep(&key_params, ";"))) { char *method = NULL; char *info = NULL; method = strsep(&key_param, ":"); info = strsep(&key_param, ";"); if (!strcmp(method, "inline")) { key_salt = strsep(&info, "|"); lifetime = strsep(&info, "|"); if (lifetime) { ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n", attr); continue; } found = 1; break; } } if (!found) { ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n"); return -1; } if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) { ast_log(LOG_WARNING, "SRTP descriptions key %d != %d\n", key_len, SRTP_MASTER_LEN); return -1; } if (!memcmp(p->remote_key, remote_key, sizeof(p->remote_key))) { ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); return 0; } memcpy(p->remote_key, remote_key, sizeof(p->remote_key)); if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) { return -1; } if (!p->tag) { ast_debug(1, "Accepting crypto tag %s\n", tag); p->tag = ast_strdup(tag); if (!p->tag) { ast_log(LOG_ERROR, "Could not allocate memory for tag\n"); return -1; } } /* Finally, rebuild the crypto line */ return sdp_crypto_offer(p, taglen); }