📄 srtp.c
字号:
/* initialize key limit to maximum value */#ifdef NO_64BIT_MATH{ uint64_t temp; temp = make64(UINT_MAX,UINT_MAX); key_limit_set(srtp->limit, temp);}#else key_limit_set(srtp->limit, 0xffffffffffffLL);#endif /* set the SSRC value */ srtp->ssrc = htonl(p->ssrc.value); /* set the security service flags */ srtp->rtp_services = p->rtp.sec_serv; srtp->rtcp_services = p->rtcp.sec_serv; /* * set direction to unknown - this flag gets checked in srtp_protect(), * srtp_unprotect(), srtp_protect_rtcp(), and srtp_unprotect_rtcp(), and * gets set appropriately if it is set to unknown. */ srtp->direction = dir_unknown; /* initialize SRTCP replay database */ rdb_init(&srtp->rtcp_rdb); /* DAM - no RTCP key limit at present */ /* initialize keys */ err = srtp_stream_init_keys(srtp, p->key); if (err) return err; return err_status_ok; } /* * srtp_event_reporter is an event handler function that merely * reports the events that are reported by the callbacks */ void srtp_event_reporter(srtp_event_data_t *data) { err_report(err_level_warning, "srtp: in stream 0x%x: ", data->stream->ssrc); switch(data->event) { case event_ssrc_collision: err_report(err_level_warning, "\tSSRC collision\n"); break; case event_key_soft_limit: err_report(err_level_warning, "\tkey usage soft limit reached\n"); break; case event_key_hard_limit: err_report(err_level_warning, "\tkey usage hard limit reached\n"); break; case event_packet_index_limit: err_report(err_level_warning, "\tpacket index limit reached\n"); break; default: err_report(err_level_warning, "\tunknown event reported to handler\n"); } } /* * srtp_event_handler is a global variable holding a pointer to the * event handler function; this function is called for any unexpected * event that needs to be handled out of the SRTP data path. see * srtp_event_t in srtp.h for more info * * it is okay to set srtp_event_handler to NULL, but we set * it to the srtp_event_reporter. */ static srtp_event_handler_func_t *srtp_event_handler = srtp_event_reporter; err_status_t srtp_install_event_handler(srtp_event_handler_func_t func) { /* * note that we accept NULL arguments intentionally - calling this * function with a NULL arguments removes an event handler that's * been previously installed */ /* set global event handling function */ srtp_event_handler = func; return err_status_ok; } err_status_t srtp_protect(srtp_ctx_t *ctx, void *rtp_hdr, int *pkt_octet_len) { srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; uint32_t *enc_start; /* pointer to start of encrypted portion */ uint32_t *auth_start; /* pointer to start of auth. portion */ unsigned enc_octet_len = 0; /* number of octets in encrypted portion */ xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ int delta; /* delta of local pkt idx and that in hdr */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ err_status_t status; int tag_len; srtp_stream_ctx_t *stream; int prefix_len; debug_print(mod_srtp, "function srtp_protect", NULL); /* we assume the hdr is 32-bit aligned to start */ /* check the packet length - it must at least contain a full header */ if (*pkt_octet_len < octets_in_rtp_header) return err_status_bad_param; /* * 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 a template 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) { srtp_stream_ctx_t *new_stream; /* allocate and initialize a new stream */ 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 direction to outbound */ new_stream->direction = dir_srtp_sender; /* set stream (the pointer used in this function) */ stream = new_stream; } else { /* no template stream, so we return an error */ return err_status_no_ctx; } } /* * verify that stream is for sending 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. */ if (stream->direction != dir_srtp_sender) { if (stream->direction == dir_unknown) { stream->direction = dir_srtp_sender; } else { srtp_handle_event(ctx, stream, event_ssrc_collision); } } /* * update the key usage limit, and check it to make sure that we * didn't just hit either the soft limit or the hard limit, and call * the event handler if we hit either. */ switch(key_limit_update(stream->limit)) { case key_event_normal: break; case key_event_soft_limit: srtp_handle_event(ctx, stream, event_key_soft_limit); break; case key_event_hard_limit: srtp_handle_event(ctx, stream, event_key_hard_limit); return err_status_key_expired; default: break; } /* get tag length from stream */ tag_len = auth_get_tag_length(stream->rtp_auth); /* * find starting point for encryption and length of data to be * encrypted - the encrypted portion starts after the rtp header * extension, if present; otherwise, it starts after the last csrc, * if any are present * * if we're not providing confidentiality, set enc_start to NULL */ if (stream->rtp_services & sec_serv_conf) { enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; if (hdr->x == 1) { srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; enc_start += (ntohs(xtn_hdr->length) + 1); } enc_octet_len = (unsigned int)(*pkt_octet_len - ((enc_start - (uint32_t *)hdr) << 2)); } else { enc_start = NULL; } /* * if we're providing authentication, set the auth_start and auth_tag * pointers to the proper locations; otherwise, set auth_start to NULL * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { auth_start = (uint32_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len; } else { auth_start = NULL; auth_tag = NULL; } /* * estimate the packet index using the start of the replay window * and the sequence number from the header */ delta = rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq)); status = rdbx_check(&stream->rtp_rdbx, delta); if (status) return status; /* we've been asked to reuse an index */ rdbx_add_index(&stream->rtp_rdbx, delta);#ifdef NO_64BIT_MATH debug_print2(mod_srtp, "estimated packet index: %08x%08x", high32(est),low32(est));#else debug_print(mod_srtp, "estimated packet index: %016llx", est);#endif /* * if we're using rindael counter mode, set nonce and seq */ if (stream->rtp_cipher->type == &aes_icm) { v128_t iv; iv.v32[0] = 0; iv.v32[1] = hdr->ssrc;#ifdef NO_64BIT_MATH iv.v64[1] = be64_to_cpu(make64((high32(est) << 16) | (low32(est) >> 16), low32(est) << 16));#else iv.v64[1] = be64_to_cpu(est << 16);#endif status = cipher_set_iv(stream->rtp_cipher, &iv); } else { v128_t iv; /* otherwise, set the index to est */ #ifdef NO_64BIT_MATH iv.v32[0] = 0; iv.v32[1] = 0;#else iv.v64[0] = 0;#endif iv.v64[1] = be64_to_cpu(est); status = cipher_set_iv(stream->rtp_cipher, &iv); } if (status) return err_status_cipher_fail; /* shift est, put into network byte order */#ifdef NO_64BIT_MATH est = be64_to_cpu(make64((high32(est) << 16) | (low32(est) >> 16), low32(est) << 16));#else est = be64_to_cpu(est << 16);#endif /* * if we're authenticating using a universal hash, put the keystream * prefix into the authentication tag */ if (auth_start) { prefix_len = auth_get_prefix_length(stream->rtp_auth); if (prefix_len) { status = cipher_output(stream->rtp_cipher, auth_tag, prefix_len); if (status) return err_status_cipher_fail; debug_print(mod_srtp, "keystream prefix: %s", octet_string_hex_string(auth_tag, prefix_len)); } } /* if we're encrypting, exor keystream into the message */ if (enc_start) { status = cipher_encrypt(stream->rtp_cipher, (uint8_t *)enc_start, &enc_octet_len); if (status) return err_status_cipher_fail; } /* * if we're authenticating, run authentication function and put result * into the auth_tag */ if (auth_start) { /* initialize auth func context */ status = auth_start(stream->rtp_auth); if (status) return status; /* run auth func over packet */ status = auth_update(stream->rtp_auth, (uint8_t *)auth_start, *pkt_octet_len); if (status) return status; /* run auth func over ROC, put result into auth_tag */ debug_print(mod_srtp, "estimated packet index: %016llx", est); status = auth_compute(stream->rtp_auth, (uint8_t *)&est, 4, auth_tag); debug_print(mod_srtp, "srtp auth tag: %s", octet_string_hex_string(auth_tag, tag_len)); if (status) return err_status_auth_fail; } if (auth_tag) { /* increase the packet length by the length of the auth tag */ *pkt_octet_len += tag_len; } return err_status_ok; }err_status_tsrtp_unprotect(srtp_ctx_t *ctx, void *srtp_hdr, int *pkt_octet_len) { srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; uint32_t *enc_start; /* pointer to start of encrypted portion */ uint32_t *auth_start; /* pointer to start of auth. portion */ unsigned enc_octet_len = 0;/* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ int delta; /* delta of local pkt idx and that in hdr */ v128_t iv; err_status_t status; srtp_stream_ctx_t *stream; uint8_t tmp_tag[SRTP_MAX_TAG_LEN]; int tag_len, prefix_len; debug_print(mod_srtp, "function srtp_unprotect", NULL); /* we assume the hdr is 32-bit aligned to start */ /* check the packet length - it must at least contain a full header */ if (*pkt_octet_len < octets_in_rtp_header) return err_status_bad_param; /* * 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, "using provisional stream (SSRC: 0x%08x)", hdr->ssrc); /* * set estimated packet index to sequence number from header, * and set delta equal to the same value */#ifdef NO_64BIT_MATH est = (xtd_seq_num_t) make64(0,ntohs(hdr->seq)); delta = low32(est);#else est = (xtd_seq_num_t) ntohs(hdr->seq); delta = (int)est;#endif } else { /* * no stream corresponding to SSRC found, and we don't do * key-sharing, so return an error */ return err_status_no_ctx; } } else { /* estimate packet index from seq. num. in header */ delta = rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq)); /* check replay database */ status = rdbx_check(&stream->rtp_rdbx, delta); if (status) return status; }#ifdef NO_64BIT_MATH debug_print2(mod_srtp, "estimated u_packet index: %08x%08x", high32(est),low32(est));#else debug_print(mod_srtp, "estimated u_packet index: %016llx", est);#endif /* get tag length from stream */ tag_len = auth_get_tag_length(stream->rtp_auth); /* * set the cipher's IV properly, depending on whatever cipher we * happen to be using */ if (stream->rtp_cipher->type == &aes_icm) { /* aes counter mode */ iv.v32[0] = 0; iv.v32[1] = hdr->ssrc; /* still in network order */#ifdef NO_64BIT_MATH iv.v64[1] = be64_to_cpu(make64((high32(est) << 16) | (low32(est) >> 16), low32(est) << 16));#else iv.v64[1] = be64_to_cpu(est << 16);#endif status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtp_cipher->state, &iv); } else { /* no particular format - set the iv to the pakcet index */ #ifdef NO_64BIT_MATH iv.v32[0] = 0; iv.v32[1] = 0;#else iv.v64[0] = 0;#endif iv.v64[1] = be64_to_cpu(est); status = cipher_set_iv(stream->rtp_cipher, &iv); } if (status) return err_status_cipher_fail; /* shift est, put into network byte order */#ifdef NO_64BIT_MATH est = be64_to_cpu(make64((high32(est) << 16) | (low32(est) >> 16), low32(est) << 16));#else est = be64_to_cpu(est << 16);#endif /* * find starting point for decryption and length of data to be * decrypted - the encrypted portion starts after the rtp header * extension, if present; otherwise, it starts after the last csrc, * if any are present * * if we're not providing confidentiality, set enc_start to NULL */ if (stream->rtp_services & sec_serv_conf) { enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; if (hdr->x == 1) { srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; enc_start += (ntohs(xtn_hdr->length) + 1); } enc_octet_len = (uint32_t)(*pkt_octet_len - tag_len - ((enc_start - (uint32_t *)hdr) << 2)); } else { enc_start = NULL; } /* * if we're providing authentication, set the auth_start and auth_tag * pointers to the proper locations; otherwise, set auth_start to NULL * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { auth_start = (uint32_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -