[Pkg-voip-commits] r7763 - in /asterisk/branches/lenny/debian: changelog patches/iax2-encryption-fix patches/series
paravoid at alioth.debian.org
paravoid at alioth.debian.org
Sat Nov 7 07:43:15 UTC 2009
Author: paravoid
Date: Sat Nov 7 07:43:14 2009
New Revision: 7763
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=7763
Log:
Fix IAX2 encryption severe breakage. Thanks to Francois Marier for finding
the upstream bug report and preparing a fix. (Closes: #521641)
Added:
asterisk/branches/lenny/debian/patches/iax2-encryption-fix
Modified:
asterisk/branches/lenny/debian/changelog
asterisk/branches/lenny/debian/patches/series
Modified: asterisk/branches/lenny/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny/debian/changelog?rev=7763&op=diff
==============================================================================
--- asterisk/branches/lenny/debian/changelog (original)
+++ asterisk/branches/lenny/debian/changelog Sat Nov 7 07:43:14 2009
@@ -7,8 +7,10 @@
(Closes: #522528)
- "SIP responses expose valid usernames", AST-2009-008.
(Closes: #554487)
-
- -- Faidon Liambotis <paravoid at debian.org> Sat, 07 Nov 2009 09:34:02 +0200
+ * Fix IAX2 encryption severe breakage. Thanks to Francois Marier for finding
+ the upstream bug report and preparing a fix. (Closes: #521641)
+
+ -- Faidon Liambotis <paravoid at debian.org> Sat, 07 Nov 2009 09:42:56 +0200
asterisk (1:1.4.21.2~dfsg-3) unstable; urgency=medium
Added: asterisk/branches/lenny/debian/patches/iax2-encryption-fix
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny/debian/patches/iax2-encryption-fix?rev=7763&op=file
==============================================================================
--- asterisk/branches/lenny/debian/patches/iax2-encryption-fix (added)
+++ asterisk/branches/lenny/debian/patches/iax2-encryption-fix Sat Nov 7 07:43:14 2009
@@ -1,0 +1,254 @@
+encrypted IAX2 during packet loss causes decryption to fail on
+retransmitted frames
+
+If an iax channel is encrypted, and a retransmit frame is sent, that
+packet's iseqno is updated while it is encrypted. This causes the
+entire frame to be corrupted. When the corrupted frame is sent, the
+other side decrypts it and sends a VNAK back because the decrypted
+frame doesn't make any sense. When we get the VNAK, we look through
+the sent queue and send the same corrupted frame causing a loop. To
+fix this, encrypted frames requiring retransmission are decrypted,
+updated, then re-encrypted. Since key-rotation may change the key held
+by the pvt struct, the keys used for encryption/decryption are held
+within the iax_frame to guarantee they remain correct.
+
+(source: http://bugs.digium.com/view.php?id=14607)
+
+ -- Francois Marier <francois at debian.org>
+
+--- a/channels/chan_iax2.c
++++ b/channels/chan_iax2.c
+@@ -574,7 +574,9 @@ struct chan_iax2_pvt {
+ 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];
+@@ -860,6 +862,10 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
+ static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime);
+ static void prune_peers(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",
+ .description = tdesc,
+@@ -2134,11 +2140,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;
+ }
+
+@@ -4098,10 +4115,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, 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)
+@@ -4254,7 +4280,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);
+@@ -4349,6 +4375,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)
+@@ -4402,6 +4429,10 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
+ 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");
+ }
+@@ -5591,7 +5622,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, 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;
+@@ -5631,8 +5662,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) {
+@@ -5673,7 +5705,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))) {
+@@ -5684,7 +5716,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;
+@@ -5703,7 +5735,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) {
+@@ -6322,9 +6354,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);
+--- 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;
+@@ -86,41 +87,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 */
++ 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;
Modified: asterisk/branches/lenny/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/lenny/debian/patches/series?rev=7763&op=diff
==============================================================================
--- asterisk/branches/lenny/debian/patches/series (original)
+++ asterisk/branches/lenny/debian/patches/series Sat Nov 7 07:43:14 2009
@@ -89,6 +89,8 @@
zap-fix-cause34
### lenny fixes
+iax2-encryption-fix
+
AST-2009-001
r132790
More information about the Pkg-voip-commits
mailing list