Index: channels/iax2-parser.h =================================================================== --- channels/iax2-parser.h (révision 181339) +++ channels/iax2-parser.h (révision 181340) @@ -19,6 +19,7 @@ #define _IAX2_PARSER_H #include "asterisk/linkedlists.h" +#include "asterisk/aes.h" struct iax_ies { char *called_number; @@ -86,41 +87,49 @@ 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 */ + aes_encrypt_ctx ecx; + /*! store decrypt key which corresponds to ecx */ + aes_decrypt_ctx 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; Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (révision 181339) +++ channels/chan_iax2.c (révision 181340) @@ -576,7 +576,9 @@ int encmethods; /*! Encryption AES-128 Key */ aes_encrypt_ctx ecx; - /*! Decryption AES-128 Key */ + /*! Decryption AES-128 Key corresponding to ecx */ + aes_decrypt_ctx mydcx; + /*! Decryption AES-128 Key used to decrypt peer frames */ aes_decrypt_ctx dcx; /*! 32 bytes of semi-random data */ unsigned char semirand[32]; @@ -869,6 +871,10 @@ static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime); static void prune_peers(void); static void prune_users(void); +static int decode_frame(aes_decrypt_ctx *dcx, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen); +static int encrypt_frame(aes_encrypt_ctx *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", @@ -2254,11 +2260,22 @@ { /* 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; } @@ -4289,10 +4306,19 @@ return 0; } -static void build_enc_keys(const unsigned char *digest, aes_encrypt_ctx *ecx, aes_decrypt_ctx *dcx) +static void build_encryption_keys(const unsigned char *digest, struct chan_iax2_pvt *pvt) { - aes_encrypt_key128(digest, ecx); - aes_decrypt_key128(digest, dcx); + build_ecx_key(digest, pvt); + aes_decrypt_key128(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 */ + aes_encrypt_key128(digest, &pvt->ecx); + aes_decrypt_key128(digest, &pvt->mydcx); } static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len, aes_decrypt_ctx *dcx) @@ -4445,7 +4471,7 @@ 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); @@ -4540,6 +4566,7 @@ fr->callno = pvt->callno; fr->transfer = transfer; fr->final = final; + fr->encmethods = 0; if (!sendmini) { /* We need a full frame */ if (seqno > -1) @@ -4593,6 +4620,10 @@ iax_showframe(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"); } @@ -5785,7 +5816,7 @@ 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, aes_encrypt_ctx *ecx, aes_decrypt_ctx *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; @@ -5825,8 +5856,9 @@ /* 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) { @@ -5867,7 +5899,7 @@ /* 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))) { @@ -5878,7 +5910,7 @@ && (!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; @@ -5897,7 +5929,7 @@ 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) { @@ -6528,9 +6560,9 @@ 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);