Merge pull request #136 from fancycode/unprotect_empty_payload

Allow empty payloads when unprotecting.
diff --git a/srtp/srtp.c b/srtp/srtp.c
index f60c5fb..c9a5bee 100644
--- a/srtp/srtp.c
+++ b/srtp/srtp.c
@@ -141,6 +141,33 @@
     return rv;
 }
 
+/* Release (maybe partially allocated) stream. */
+static void
+srtp_stream_free(srtp_stream_ctx_t *str) {
+  if (str->rtp_xtn_hdr_cipher) {
+    srtp_cipher_dealloc(str->rtp_xtn_hdr_cipher);
+  }
+  if (str->enc_xtn_hdr) {
+    srtp_crypto_free(str->enc_xtn_hdr);
+  }
+  if (str->rtcp_auth) {
+    auth_dealloc(str->rtcp_auth);
+  }
+  if (str->rtcp_cipher) {
+    srtp_cipher_dealloc(str->rtcp_cipher);
+  }
+  if (str->limit) {
+    srtp_crypto_free(str->limit);
+  }
+  if (str->rtp_auth) {
+    auth_dealloc(str->rtp_auth);
+  }
+  if (str->rtp_cipher) {
+    srtp_cipher_dealloc(str->rtp_cipher);
+  }
+  srtp_crypto_free(str);
+}
+
 srtp_err_status_t
 srtp_stream_alloc(srtp_stream_ctx_t **str_ptr,
 		  const srtp_policy_t *p) {
@@ -159,15 +186,17 @@
   str = (srtp_stream_ctx_t *) srtp_crypto_alloc(sizeof(srtp_stream_ctx_t));
   if (str == NULL)
     return srtp_err_status_alloc_fail;
-  *str_ptr = str;  
-  
+
+  memset(str, 0, sizeof(srtp_stream_ctx_t));
+  *str_ptr = str;
+
   /* allocate cipher */
   stat = srtp_crypto_kernel_alloc_cipher(p->rtp.cipher_type, 
 				    &str->rtp_cipher, 
 				    p->rtp.cipher_key_len,
 				    p->rtp.auth_tag_len); 
   if (stat) {
-    srtp_crypto_free(str);
+    srtp_stream_free(str);
     return stat;
   }
 
@@ -177,17 +206,14 @@
 				  p->rtp.auth_key_len, 
 				  p->rtp.auth_tag_len); 
   if (stat) {
-    srtp_cipher_dealloc(str->rtp_cipher);
-    srtp_crypto_free(str);
+    srtp_stream_free(str);
     return stat;
   }
   
   /* allocate key limit structure */
   str->limit = (srtp_key_limit_ctx_t*) srtp_crypto_alloc(sizeof(srtp_key_limit_ctx_t));
   if (str->limit == NULL) {
-    auth_dealloc(str->rtp_auth);
-    srtp_cipher_dealloc(str->rtp_cipher);
-    srtp_crypto_free(str); 
+    srtp_stream_free(str);
     return srtp_err_status_alloc_fail;
   }
 
@@ -200,10 +226,7 @@
 				    p->rtcp.cipher_key_len, 
 				    p->rtcp.auth_tag_len); 
   if (stat) {
-    auth_dealloc(str->rtp_auth);
-    srtp_cipher_dealloc(str->rtp_cipher);
-    srtp_crypto_free(str->limit);
-    srtp_crypto_free(str);
+    srtp_stream_free(str);
     return stat;
   }
 
@@ -213,24 +236,15 @@
 				  p->rtcp.auth_key_len, 
 				  p->rtcp.auth_tag_len); 
   if (stat) {
-    srtp_cipher_dealloc(str->rtcp_cipher);
-    auth_dealloc(str->rtp_auth);
-    srtp_cipher_dealloc(str->rtp_cipher);
-    srtp_crypto_free(str->limit);
-    srtp_crypto_free(str);
-   return stat;
+    srtp_stream_free(str);
+    return stat;
   }  
 
   /* allocate ekt data associated with stream */
   stat = srtp_ekt_alloc(&str->ekt, p->ekt);
   if (stat) {
-    auth_dealloc(str->rtcp_auth);
-    srtp_cipher_dealloc(str->rtcp_cipher);
-    auth_dealloc(str->rtp_auth);
-    srtp_cipher_dealloc(str->rtp_cipher);
-    srtp_crypto_free(str->limit);
-    srtp_crypto_free(str);
-   return stat;    
+    srtp_stream_free(str);
+    return stat;
   }
 
   if (p->enc_xtn_hdr && p->enc_xtn_hdr_count > 0) {
@@ -239,12 +253,7 @@
 
     str->enc_xtn_hdr = (int*) srtp_crypto_alloc(p->enc_xtn_hdr_count * sizeof(p->enc_xtn_hdr[0]));
     if (!str->enc_xtn_hdr) {
-      auth_dealloc(str->rtcp_auth);
-      srtp_cipher_dealloc(str->rtcp_cipher);
-      auth_dealloc(str->rtp_auth);
-      srtp_cipher_dealloc(str->rtp_cipher);
-      srtp_crypto_free(str->limit);
-      srtp_crypto_free(str);
+      srtp_stream_free(str);
       return srtp_err_status_alloc_fail;
     }
     memcpy(str->enc_xtn_hdr, p->enc_xtn_hdr, p->enc_xtn_hdr_count * sizeof(p->enc_xtn_hdr[0]));
@@ -272,13 +281,7 @@
               enc_xtn_hdr_cipher_key_len,
               0);
     if (stat) {
-      srtp_crypto_free(str->enc_xtn_hdr);
-      auth_dealloc(str->rtcp_auth);
-      srtp_cipher_dealloc(str->rtcp_cipher);
-      auth_dealloc(str->rtp_auth);
-      srtp_cipher_dealloc(str->rtp_cipher);
-      srtp_crypto_free(str->limit);
-      srtp_crypto_free(str);
+      srtp_stream_free(str);
       return stat;
     }
   } else {
@@ -819,6 +822,15 @@
       octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
       return srtp_err_status_init_fail;
     }
+
+    if (xtn_hdr_kdf != &kdf) {
+      /* release memory for custom header extension encryption kdf */
+      stat = srtp_kdf_clear(xtn_hdr_kdf);
+      if (stat) {
+        octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+        return srtp_err_status_init_fail;
+      }
+    }
   }
 
   /* generate authentication key */
diff --git a/test/srtp_driver.c b/test/srtp_driver.c
index 44bd502..4929ca4 100644
--- a/test/srtp_driver.c
+++ b/test/srtp_driver.c
@@ -1651,8 +1651,11 @@
      * unprotect ciphertext, then compare with plaintext
      */
     status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
-    if (status || (len != 28))
+    if (status) {
         return status;
+    } else if (len != sizeof(srtp_plaintext_ref)) {
+        return srtp_err_status_fail;
+    }
 
     if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
         return srtp_err_status_fail;
@@ -1670,6 +1673,7 @@
 
 
 #ifdef OPENSSL
+
 /*
  * Headers of test vectors taken from RFC 6904, Appendix A
  */
@@ -1766,8 +1770,11 @@
      * unprotect ciphertext, then compare with plaintext
      */
     status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
-    if (status || (len != 28))
+    if (status) {
         return status;
+    } else if (len != sizeof(srtp_plaintext_ref)) {
+        return srtp_err_status_fail;
+    }
 
     if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
         return srtp_err_status_fail;
@@ -2231,6 +2238,7 @@
   srtp_t srtp_snd, srtp_recv;
   srtp_policy_t policy;
 
+  memset(&policy, 0, sizeof(policy));
   srtp_crypto_policy_set_rtp_default(&policy.rtp);
   srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
   policy.ekt = NULL;