summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_iax2.c59
-rw-r--r--channels/iax2-parser.h45
2 files changed, 72 insertions, 32 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 46b3b5ff8..d8e00881e 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -690,7 +690,9 @@ struct chan_iax2_pvt {
int encmethods;
/*! Encryption AES-128 Key */
ast_aes_encrypt_key ecx;
- /*! Decryption AES-128 Key */
+ /*! Decryption AES-128 Key corresponding to ecx */
+ ast_aes_decrypt_key mydcx;
+ /*! Decryption AES-128 Key used to decrypt peer frames */
ast_aes_decrypt_key dcx;
/*! scheduler id associated with iax_key_rotate
* for encrypted calls*/
@@ -1059,6 +1061,9 @@ static void iax2_free_variable_datastore(void *);
static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
static int acf_channel_write(struct ast_channel *chan, const char *function, char *data, const char *value);
+static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen);
+static int encrypt_frame(ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh, unsigned char *poo, int *datalen);
+static void build_ecx_key(const unsigned char *digest, struct chan_iax2_pvt *pvt);
static const struct ast_channel_tech iax2_tech = {
.type = "IAX2",
@@ -2528,11 +2533,22 @@ static int update_packet(struct iax_frame *f)
{
/* Called with iaxsl lock held, and iaxs[callno] non-NULL */
struct ast_iax2_full_hdr *fh = f->data;
+ struct ast_frame af;
+
+ /* if frame is encrypted. decrypt before updating it. */
+ if (f->encmethods) {
+ decode_frame(&f->mydcx, fh, &af, &f->datalen);
+ }
/* Mark this as a retransmission */
fh->dcallno = ntohs(IAX_FLAG_RETRANS | f->dcallno);
/* Update iseqno */
f->iseqno = iaxs[f->callno]->iseqno;
fh->iseqno = f->iseqno;
+
+ /* Now re-encrypt the frame */
+ if (f->encmethods) {
+ encrypt_frame(&f->ecx, fh, f->semirand, &f->datalen);
+ }
return 0;
}
@@ -4104,7 +4120,7 @@ static int iax2_key_rotate(const void *vpvt)
res = send_command(pvt, AST_FRAME_IAX, IAX_COMMAND_RTKEY, 0, ied.buf, ied.pos, -1);
- ast_aes_encrypt_key((unsigned char *) key, &pvt->ecx);
+ build_ecx_key((unsigned char *) key, pvt);
ast_mutex_unlock(&iaxsl[pvt->callno]);
@@ -4840,10 +4856,19 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
return 0;
}
-static void build_enc_keys(const unsigned char *digest, ast_aes_encrypt_key *ecx, ast_aes_decrypt_key *dcx)
+static void build_encryption_keys(const unsigned char *digest, struct chan_iax2_pvt *pvt)
{
- ast_aes_encrypt_key(digest, ecx);
- ast_aes_decrypt_key(digest, dcx);
+ build_ecx_key(digest, pvt);
+ ast_aes_decrypt_key(digest, &pvt->dcx);
+}
+
+static void build_ecx_key(const unsigned char *digest, struct chan_iax2_pvt *pvt)
+{
+ /* it is required to hold the corresponding decrypt key to our encrypt key
+ * in the pvt struct because queued frames occasionally need to be decrypted and
+ * re-encrypted when updated for a retransmission */
+ ast_aes_encrypt_key(digest, &pvt->ecx);
+ ast_aes_decrypt_key(digest, &pvt->mydcx);
}
static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len, ast_aes_decrypt_key *dcx)
@@ -4996,7 +5021,7 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
MD5Final(digest, &md5);
- build_enc_keys(digest, &iaxs[callno]->ecx, &iaxs[callno]->dcx);
+ build_encryption_keys(digest, iaxs[callno]);
res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
if (!res) {
ast_set_flag(iaxs[callno], IAX_KEYPOPULATED);
@@ -5101,6 +5126,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
fr->callno = pvt->callno;
fr->transfer = transfer;
fr->final = final;
+ fr->encmethods = 0;
if (!sendmini) {
/* We need a full frame */
if (seqno > -1)
@@ -5152,6 +5178,10 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
else
iax_outputframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
encrypt_frame(&pvt->ecx, fh, pvt->semirand, &fr->datalen);
+ fr->encmethods = pvt->encmethods;
+ fr->ecx = pvt->ecx;
+ fr->mydcx = pvt->mydcx;
+ memcpy(fr->semirand, pvt->semirand, sizeof(fr->semirand));
} else
ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
}
@@ -6648,7 +6678,7 @@ return_unref:
return res;
}
-static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, ast_aes_encrypt_key *ecx, ast_aes_decrypt_key *dcx)
+static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, struct chan_iax2_pvt *pvt)
{
int res = -1;
int x;
@@ -6688,8 +6718,9 @@ static int authenticate(const char *challenge, const char *secret, const char *k
/* If they support md5, authenticate with it. */
for (x=0;x<16;x++)
sprintf(digres + (x << 1), "%2.2x", digest[x]); /* safe */
- if (ecx && dcx)
- build_enc_keys(digest, ecx, dcx);
+ if (pvt) {
+ build_encryption_keys(digest, pvt);
+ }
iax_ie_append_str(ied, IAX_IE_MD5_RESULT, digres);
res = 0;
} else if (authmethods & IAX_AUTH_PLAINTEXT) {
@@ -6730,7 +6761,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
/* Check for override RSA authentication first */
if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
/* Normal password authentication */
- res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, &p->ecx, &p->dcx);
+ res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, p);
} else {
struct ao2_iterator i = ao2_iterator_init(peers, 0);
while ((peer = ao2_iterator_next(&i))) {
@@ -6741,7 +6772,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
&& (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
/* No specified host, or this is our host */
) {
- res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
+ res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, p);
if (!res) {
peer_unref(peer);
break;
@@ -6760,7 +6791,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
peer_unref(peer);
return -1;
}
- res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
+ res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, p);
peer_unref(peer);
}
if (!peer) {
@@ -7454,9 +7485,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
char tmpkey[256];
ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
tmpkey[strlen(tmpkey) - 1] = '\0';
- res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL, NULL);
+ res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL);
} else
- res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL, NULL);
+ res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL);
if (!res) {
reg->regstate = REG_STATE_AUTHSENT;
return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
diff --git a/channels/iax2-parser.h b/channels/iax2-parser.h
index e40669d3d..e75cd4209 100644
--- a/channels/iax2-parser.h
+++ b/channels/iax2-parser.h
@@ -19,6 +19,7 @@
#define _IAX2_PARSER_H
#include "asterisk/linkedlists.h"
+#include "asterisk/aes.h"
struct iax_ies {
char *called_number;
@@ -89,41 +90,49 @@ struct iax_frame {
int sockfd;
#endif
- /* /Our/ call number */
+ /*! /Our/ call number */
unsigned short callno;
- /* /Their/ call number */
+ /*! /Their/ call number */
unsigned short dcallno;
- /* Start of raw frame (outgoing only) */
+ /*! Start of raw frame (outgoing only) */
void *data;
- /* Length of frame (outgoing only) */
+ /*! Length of frame (outgoing only) */
int datalen;
- /* How many retries so far? */
+ /*! How many retries so far? */
int retries;
- /* Outgoing relative timestamp (ms) */
+ /*! Outgoing relative timestamp (ms) */
unsigned int ts;
- /* How long to wait before retrying */
+ /*! How long to wait before retrying */
int retrytime;
- /* Are we received out of order? */
+ /*! Are we received out of order? */
unsigned int outoforder:1;
- /* Have we been sent at all yet? */
+ /*! Have we been sent at all yet? */
unsigned int sentyet:1;
- /* Non-zero if should be sent to transfer peer */
+ /*! Non-zero if should be sent to transfer peer */
unsigned int transfer:1;
- /* Non-zero if this is the final message */
+ /*! Non-zero if this is the final message */
unsigned int final:1;
- /* Ingress or outgres */
+ /*! Ingress or outgres */
unsigned int direction:2;
- /* Can this frame be cached? */
+ /*! Can this frame be cached? */
unsigned int cacheable:1;
- /* Outgoing Packet sequence number */
+ /*! Outgoing Packet sequence number */
int oseqno;
- /* Next expected incoming packet sequence number */
+ /*! Next expected incoming packet sequence number */
int iseqno;
- /* Retransmission ID */
+ /*! Retransmission ID */
int retrans;
- /* Easy linking */
+ /*! is this packet encrypted or not. if set this varible holds encryption methods*/
+ int encmethods;
+ /*! store encrypt key */
+ ast_aes_encrypt_key ecx;
+ /*! store decrypt key which corresponds to ecx */
+ ast_aes_decrypt_key mydcx;
+ /*! random data for encryption pad */
+ unsigned char semirand[32];
+ /*! Easy linking */
AST_LIST_ENTRY(iax_frame) list;
- /* Actual, isolated frame header */
+ /*! Actual, isolated frame header */
struct ast_frame af;
/*! Amount of space _allocated_ for data */
size_t afdatalen;