[asterisk-dev] AstriDevCon Recap - IAX2 RENEW for encryption

Steve Kann stevek at stevek.com
Thu May 31 11:36:44 MST 2007


Russell Bryant wrote:
> Greetings,
>
> One of the topics discussed at the developer conference was the method 
> used for IAX2 encryption.  We wanted to ensure that the method we are 
> using is actually secure.  I have summarized what came out of the 
> discussion below.  Comments are welcome, as always.
>
> From this discussion, we need to make two changes.  One is an 
> implementation issue, and the other is a protocol level issue.  The 
> protocol level issue needs to get resolved quickly so that we can get 
> it in the first version of the RFC, since IAX2 encryption is in there.
>
> 1) We should use a better random number generator.  Most of the places 
> in Asterisk are using the ast_random() wrapper, so changing the method 
> in one place should affect every usage.
>
> Currently, we use random(), which is better than rand(), but we seed 
> it with the process ID and time.  We should just change the code to 
> open and read from /dev/urandom where it is available.
>
> 2) This issue is related to the key used for encryption.  Here is a 
> basic rundown on how it works right now:
>
> a)  ====== NEW =====> (not encrypted)
>
> A NEW packet is sent to initiate a call, and this message contains the 
> ENCRYPTION information element to indicate which methods of IAX2 
> encryption are supported for this call.
>
> b) <===== AUTHREQ ===== (not encrypted)
>
> An AUTHREQ is sent to request authentication for the call.  In this 
> message, there are two information elements related to encryption for 
> the call.
>
> The first is the ENCRYPTION information element.  If this is present, 
> it contains a single encryption method that the peer has agreed to use 
> for the call (Currently, only AES128 is defined for use).
>
> The other is the CHALLENGE information element.  This contains random 
> data.  The encryption key that both sides will begin using is the MD5 
> hash of this challenge and the shared secret.
>
> c) ====== AUTHREP =====> (encrypted)
>
> This message is sent with the authentication credentials as normal. 
> However, it is encrypted with the key generated by taking the MD5 hash 
> of the CHALLENGE and the shared secret.
>
> If the incorrect key is used, the other side will get invalid data 
> when it tries to decrypt this message.
>
> d) ... Rest of the call ... (encrypted)
>
> Now, here is where a change needs to be made.  Once the call is 
> established, there is no way to change the key being used.  An 
> information element, ENCKEY has been defined for containing a new 
> encryption key, but there is no message that this information element 
> can be sent in.  To resolve this, we can do the following:
>
> Add a new IAX message type, RENEW, that can be sent during a call.  If 
> a RENEW is received during an encrypted call and contains the ENCKEY 
> information element, immediately change the key used to decrypt the 
> traffic coming from the other side to use this key.
>
> A RENEW can be explicitly acknowledged by a peer using an ACK, or it 
> can be implicitly acknowledged by the peer sending its own RENEW.  
> Also, it should be noted as a best practice to send a RENEW as soon as 
> the call is established, as well as every few minutes.  (I chose a few 
> minutes here arbitrarily.  If you have more insight into what would be 
> a good choice here, please let me know!)

3 comments here:

1) At the IAX2 transport protocol level, like any other frame, RENEW 
would be acknowledged by either an explicit or implicit ACK -- no need 
for much discussion there.

2) Semantically, though, the receiver of the RENEW should probably reply 
with an ACCEPT.  This is mainly because we also have discussed using 
RENEW as a means of renegotiating formats (incl codecs and a better 
mechanism for defining these).  The ACCEPT would be necessary for that 
negotiation process.

3) I'm not sure when we'd actually want to switch encryption keys, in 
each direction.   We would need to consider that there is some latency 
between when we send packets, and when they're received, and the latency 
is often going to be larger than the inter-packet interval.  
RENEW+ACCEPT probably handles this properly, but not in a backwards 
compatible way:

    a) When a sender sends a RENEW packet with a new ENCKEY IE, it shall 
be encrypted with the old key.  Subsequent packets shall be encrypted 
with the new encryption key.
    b) When the recipeient of a RENEW packet with an ENCKEY IE receives 
that key, it shall expect subsequent packets from that sender to be 
encrypted with the new key.  It also shall send an ACCEPT packet, 
encoded with the old ENCKEY, and then send subsequent packets encrypted 
with the new encryption key.
    c) When the sender of a RENEW packet receives an ACCEPT packet from 
it's peer, it shall expect all subsequent packets to be encrypted with 
the new key.

I think this covers cases except for these:

    1) If packets are delivered out-of-order, they may not be able to be 
properly decrypted.  (but, can we even tell that they're out-of-order, 
and reorder them without being able to decrypt them?).
    2) If you send a RENEW to a peer who hasn't yet implemented this, it 
will send back and INVAL;  But, if you're using the new key after that, 
it will also no longer be able to decrypt.
    3) We probably want to define which end of the call is responsible 
for, and allowed to send RENEW with ENCKEY -- and, if both sides are 
allowed, there may be "stare" race conditions we need to account for, 
where both sides send RENEW at the same time?


(1) requires a little digging (not too much), and (2) is just a question 
about whether we want to break backwards compatibility;  we may be able 
to allow this, and have the sender revert to the old key.


>
> e) Transfers
>
> Transfers are a more complicated situation.  The current RFC draft 
> does not address how to handle transfers involving encrypted 
> sessions.  Here is what we came up with for this.
>
> First of all, a transfer should not even be attempted unless both legs 
> involved in the transfer are using the same encryption method.
>
> When a TXREL or TXMEDIA is sent to release the entire stream or just 
> the media, it should contain the ENCKEY information element.  The key 
> sent here will be the key that the peer should use to decrypt the 
> packets received from the other end of the call.
>



More information about the asterisk-dev mailing list