Logo Search packages:      
Sourcecode: srtp version File versions  Download package

err_status_t srtp_unprotect_rtcp ( srtp_t  ctx,
void *  srtcp_hdr,
int *  pkt_octet_len 
)

srtp_unprotect_rtcp() is the Secure RTCP receiver-side packet processing function.

The function call srtp_unprotect_rtcp(ctx, srtp_hdr, len_ptr) verifies the Secure RTCP protection of the SRTCP packet pointed to by srtcp_hdr (which has length *len_ptr), using the SRTP session context ctx. If err_status_ok is returned, then srtcp_hdr points to the resulting RTCP packet and *len_ptr is the number of octets in that packet; otherwise, no assumptions should be made about the value of either data elements.

Warning:
This function assumes that the SRTCP packet is aligned on a 32-bit boundary.
Parameters:
ctx is a pointer to the srtp_t which applies to the particular packet.
srtcp_hdr is a pointer to the header of the SRTCP packet (before the call). After the function returns, it points to the rtp packet if err_status_ok was returned; otherwise, the value of the data to which it points is undefined.
pkt_octet_len is a pointer to the length in octets of the complete SRTCP packet (header and body) before the function call, and of the complete rtp packet after the call, if err_status_ok was returned. Otherwise, the value of the data to which it points is undefined.
Returns:
  • err_status_ok if the RTCP packet is valid.
  • err_status_auth_fail if the SRTCP packet failed the message authentication check.
  • err_status_replay_fail if the SRTCP packet is a replay (e.g. has already been processed and accepted).
  • [other] if there has been an error in the cryptographic mechanisms.

Definition at line 1588 of file srtp.c.

References err_status_auth_fail, err_status_cipher_fail, err_status_no_ctx, err_status_ok, and event_ssrc_collision.

                                                                     {
  srtcp_hdr_t *hdr = srtcp_hdr;
  uint32_t *enc_start;      /* pointer to start of encrypted portion  */
  uint32_t *auth_start;     /* pointer to start of auth. portion      */
  uint32_t *trailer;        /* pointer to start of trailer            */
  uint32_t enc_octet_len = 0;/* number of octets in encrypted portion */
  uint8_t *auth_tag = NULL; /* location of auth_tag within packet     */
  uint8_t tmp_tag[SRTP_MAX_TAG_LEN];
  err_status_t status;   
  int tag_len;
  srtp_stream_ctx_t *stream;
  int prefix_len;
  uint32_t seq_num;

  /* we assume the hdr is 32-bit aligned to start */
  /*
   * look up ssrc in srtp_stream list, and process the packet with 
   * the appropriate stream.  if we haven't seen this stream before,
   * there's only one key for this srtp_session, and the cipher
   * supports key-sharing, then we assume that a new stream using
   * that key has just started up
   */
  stream = srtp_get_stream(ctx, hdr->ssrc);
  if (stream == NULL) {
    if (ctx->stream_template != NULL) {
      stream = ctx->stream_template;
      debug_print(mod_srtp, "srtcp using provisional stream (SSRC: 0x%08x)", 
              hdr->ssrc);
    } else {
      /* no template stream, so we return an error */
      return err_status_no_ctx;
    } 
  }
  
  /* get tag length from stream context */
  tag_len = auth_get_tag_length(stream->rtcp_auth); 

  /*
   * set encryption start, encryption length, and trailer
   */
  enc_octet_len = *pkt_octet_len - 
                  (octets_in_rtcp_header + tag_len + sizeof(srtcp_trailer_t));
  /* index & E (encryption) bit follow normal data.  hdr->len
       is the number of words (32-bit) in the normal packet minus 1 */
  /* This should point trailer to the word past the end of the
       normal data. */
  /* This would need to be modified for optional mikey data */
  /*
   * NOTE: trailer is 32-bit aligned because RTCP 'packets' are always
   *   multiples of 32-bits (RFC 3550 6.1)
   */
  trailer = (uint32_t *) ((char *) hdr +
                 *pkt_octet_len -(tag_len + sizeof(srtcp_trailer_t)));
  if (*((unsigned char *) trailer) & SRTCP_E_BYTE_BIT) {
    enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header;  
  } else {
    enc_octet_len = 0;
    enc_start = NULL; /* this indicates that there's no encryption */
  }

  /* 
   * set the auth_start and auth_tag pointers to the proper locations
   * (note that srtcp *always* uses authentication, unlike srtp)
   */
  auth_start = (uint32_t *)hdr;
  auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len;

  /* 
   * check the sequence number for replays
   */
  /* this is easier than dealing with bitfield access */
  seq_num = ntohl(*trailer) & SRTCP_INDEX_MASK;
  debug_print(mod_srtp, "srtcp index: %x", seq_num);
  status = rdb_check(&stream->rtcp_rdb, seq_num);
  if (status)
    return status;

  /* 
   * if we're using aes counter mode, set nonce and seq 
   */
  if (stream->rtcp_cipher->type == &aes_icm) {
    v128_t iv;

    iv.v32[0] = 0;
    iv.v32[1] = hdr->ssrc; /* still in network order! */
    iv.v32[2] = htonl(seq_num >> 16);
    iv.v32[3] = htonl(seq_num << 16);
    status = aes_icm_set_iv(stream->rtcp_cipher->state, &iv);

  } else {  
    v128_t iv;
    
    /* otherwise, just set the index to seq_num */  
    iv.v32[0] = 0;
    iv.v32[1] = 0;
    iv.v32[2] = 0;
    iv.v32[3] = htonl(seq_num);
    status = cipher_set_iv(stream->rtcp_cipher, &iv);

  }
  if (status)
    return err_status_cipher_fail;

  /* initialize auth func context */
  auth_start(stream->rtcp_auth);

  /* run auth func over packet, put result into tmp_tag */
  status = auth_compute(stream->rtcp_auth, (uint8_t *)auth_start,  
                  *pkt_octet_len - tag_len,
                  tmp_tag);
  debug_print(mod_srtp, "srtcp computed tag:       %s", 
            octet_string_hex_string(tmp_tag, tag_len));
  if (status)
    return err_status_auth_fail;   
  
  /* compare the tag just computed with the one in the packet */
  debug_print(mod_srtp, "srtcp tag from packet:    %s", 
            octet_string_hex_string(auth_tag, tag_len));  
  if (octet_string_is_eq(tmp_tag, auth_tag, tag_len))
    return err_status_auth_fail;

  /* 
   * if we're authenticating using a universal hash, put the keystream
   * prefix into the authentication tag
   */
  prefix_len = auth_get_prefix_length(stream->rtcp_auth);    
  if (prefix_len) {
    status = cipher_output(stream->rtcp_cipher, auth_tag, prefix_len);
    debug_print(mod_srtp, "keystream prefix: %s", 
            octet_string_hex_string(auth_tag, prefix_len));
    if (status)
      return err_status_cipher_fail;
  }

  /* if we're decrypting, exor keystream into the message */
  if (enc_start) {
    status = cipher_encrypt(stream->rtcp_cipher, 
                      (uint8_t *)enc_start, &enc_octet_len);
    if (status)
      return err_status_cipher_fail;
  }

  /* decrease the packet length by the length of the auth tag and seq_num*/
  *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t));

  /* 
   * verify that stream is for received traffic - this check will
   * detect SSRC collisions, since a stream that appears in both
   * srtp_protect() and srtp_unprotect() will fail this test in one of
   * those functions.
   *
   * we do this check *after* the authentication check, so that the
   * latter check will catch any attempts to fool us into thinking
   * that we've got a collision
   */
  if (stream->direction != dir_srtp_receiver) {
    if (stream->direction == dir_unknown) {
      stream->direction = dir_srtp_receiver;
    } else {
      srtp_handle_event(ctx, stream, event_ssrc_collision);
    }
  }

  /* 
   * if the stream is a 'provisional' one, in which the template context
   * is used, then we need to allocate a new stream at this point, since
   * the authentication passed
   */
  if (stream == ctx->stream_template) {  
    srtp_stream_ctx_t *new_stream;

    /* 
     * allocate and initialize a new stream 
     * 
     * note that we indicate failure if we can't allocate the new
     * stream, and some implementations will want to not return
     * failure here
     */
    status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); 
    if (status)
      return status;
    
    /* add new stream to the head of the stream_list */
    new_stream->next = ctx->stream_list;
    ctx->stream_list = new_stream;
    
    /* set stream (the pointer used in this function) */
    stream = new_stream;
  }

  /* we've passed the authentication check, so add seq_num to the rdb */
  rdb_add_index(&stream->rtcp_rdb, seq_num);
    
    
  return err_status_ok;  
}


Generated by  Doxygen 1.6.0   Back to index