Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for cryptex #511

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/srtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ typedef struct srtp_policy_t {
uint8_t *enc_xtn_hdr; /**< List of header ids to encrypt. */
size_t enc_xtn_hdr_count; /**< Number of entries in list of header */
/**< ids. */
bool use_cryptex; /**< Encrypt header block and CSRCS with */
/**< cryptex. */
struct srtp_policy_t *next; /**< Pointer to next stream policy. */
} srtp_policy_t;

Expand Down
2 changes: 2 additions & 0 deletions include/srtp_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ typedef struct srtp_stream_ctx_t_ {
uint8_t *enc_xtn_hdr;
size_t enc_xtn_hdr_count;
uint32_t pending_roc;
bool use_cryptex;
struct srtp_stream_ctx_t_ *next; /* linked list of streams */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next was removed, I guess this slipped in while merging ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There have been a lot of changes in main, are you sure the merge went well ? All builds are failing.
Also the input buffer to the protect/unprotect functions is now const, not sure you should just cast that away and move the memory around.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think I have been too optimistic about my rebasing 😅

Wil try to get a look next week

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had a quick attempt a few weeks ago and understood that this was not an easy merge :( . Let me know if you want to discuss anything.

} strp_stream_ctx_t_;

/*
Expand Down
276 changes: 262 additions & 14 deletions srtp/srtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ static srtp_err_status_t srtp_stream_alloc(srtp_stream_ctx_t **str_ptr,
str->enc_xtn_hdr_count = 0;
}

str->use_cryptex = p->use_cryptex;

return srtp_err_status_ok;
}

Expand Down Expand Up @@ -673,6 +675,7 @@ static srtp_err_status_t srtp_stream_clone(
/* copy information about extensions header encryption */
str->enc_xtn_hdr = stream_template->enc_xtn_hdr;
str->enc_xtn_hdr_count = stream_template->enc_xtn_hdr_count;
str->use_cryptex = stream_template->use_cryptex;

return srtp_err_status_ok;
}
Expand Down Expand Up @@ -1856,6 +1859,12 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx,
size_t tag_len;
v128_t iv;
size_t aad_len;
srtp_hdr_xtnd_t *xtn_hdr = NULL;
unsigned int mki_size = 0;
uint8_t *mki_location = NULL;
int xtn_hdr_length = 0;
int xtn_profile_specific = 0;
uint32_t xtn_hdr_profile_and_value = 0;

debug_print0(mod_srtp, "function srtp_protect_aead");

Expand Down Expand Up @@ -1883,11 +1892,48 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx,
* 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 any are present.
* If cryptex is used, the encryption portions also covers the
* rtp heacer extension.
*/
enc_start = srtp_get_rtp_hdr_len(hdr);

/* Cryptex can only encrypt CSRCS if header extension is present*/
if (stream->use_cryptex && hdr->cc && !hdr->x) {
return srtp_err_status_parse_err;
}

if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp);
xtn_hdr = (srtp_hdr_xtnd_t *)(uint32_t *)hdr + uint32s_in_rtp_header +
hdr->cc;
xtn_hdr_length = ntohs(xtn_hdr->length);
xtn_profile_specific = ntohs(xtn_hdr->profile_specific);
}

/* If no header extension is present cryptex has no effect */
if (stream->use_cryptex && hdr->x) {
/* Change profiles by cryptex values */
if (xtn_profile_specific == 0xbede) {
xtn_hdr_profile_and_value = htonl(0xc0de << 16 | xtn_hdr_length);
} else if ((xtn_profile_specific & 0xfff0) == 0x1000) {
xtn_hdr_profile_and_value = htonl(0xc2de << 16 | xtn_hdr_length);
} else {
return srtp_err_status_parse_err;
}
/* Get CSRCs block position or profile if no CSRCs */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Move CSRCS so block is contiguous with extension header block */
for (unsigned char i = hdr->cc; i > 0; --i) {
csrcs[i] = csrcs[i - 1];
}
/* Move profile and length before the CSRCs */
csrcs[0] = xtn_hdr_profile_and_value;
/* Start encrypting in the CSRCS block new position */
enc_start = csrcs + 1;
} else {
enc_start = srtp_get_rtp_hdr_len(hdr);
if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp);
}
}

/* note: the passed size is without the auth tag */
Expand Down Expand Up @@ -1982,6 +2028,27 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx,
return srtp_err_status_cipher_fail;
}

/* Restore CSRCs block before sending if using cryptex */
if (stream->use_cryptex && xtn_hdr && hdr->cc) {
/* Restore CSRCS to its original position */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
for (unsigned char i = 0; i < hdr->cc; ++i)
csrcs[i] = csrcs[i + 1];
/* Restore extension header profile and length */
*(uint32_t *)xtn_hdr = xtn_hdr_profile_and_value;
}

/*
* If we're doing GCM, we need to get the tag
* and append that to the output
*/
status =
srtp_cipher_get_tag(session_keys->rtp_cipher,
(uint8_t *)enc_start + enc_octet_len, &tag_len);
if (status) {
return (srtp_err_status_cipher_fail);
}

if (stream->use_mki) {
srtp_inject_mki(srtp + enc_start + enc_octet_len, session_keys,
stream->mki_size);
Expand Down Expand Up @@ -2019,7 +2086,12 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx,
v128_t iv;
srtp_err_status_t status;
size_t tag_len;
size_t aad_len;
size_t int aad_len;
srtp_hdr_xtnd_t *xtn_hdr = NULL;
size_t xtn_hdr_length = 0;
int xtn_profile_specific = 0;
bool use_cryptex = false;
uint32_t xtn_hdr_profile_and_value = 0;

debug_print0(mod_srtp, "function srtp_unprotect_aead");

Expand All @@ -2045,9 +2117,40 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx,
return srtp_err_status_cipher_fail;
}

enc_start = srtp_get_rtp_hdr_len(hdr);
/*
* 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 cryptex is in use, the encrypted portion also covers the
* rtp header extension.
*/
if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp);
xtn_hdr = (srtp_hdr_xtnd_t *)(uint32_t *)hdr + uint32s_in_rtp_header +
hdr->cc;
xtn_hdr_length = ntohs(xtn_hdr->length);
xtn_profile_specific = ntohs(xtn_hdr->profile_specific);
}

/* Check if the profile is the one for cryptex */
if (xtn_profile_specific == 0xc0de || xtn_profile_specific == 0xc2de) {
/* Get the 4 bytes of defined by profile and length */
xtn_hdr_profile_and_value = *(uint32_t *)xtn_hdr;
/* Get CSRCs block position or profile if no CSRCs */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Move CSRCS so block is contiguous with extension header block */
for (unsigned char i = hdr->cc; i > 0; --i)
csrcs[i] = csrcs[i - 1];
/* Move defined by profile before the CSRCs block */
csrcs[0] = xtn_hdr_profile_and_value;
/* Start encrypting in the CSRCS block new position */
enc_start = csrcs + 1;
use_cryptex = 1;
} else {
enc_start = srtp_get_rtp_hdr_len(hdr);
if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp);
}
}

if (enc_start > srtp_len - tag_len - stream->mki_size) {
Expand Down Expand Up @@ -2114,6 +2217,23 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx,
return status;
}

if (use_cryptex) {
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Restore CSRCS to its original position */
for (unsigned char i = 0; i < hdr->cc; ++i) {
csrcs[i] = csrcs[i + 1];
}
/* Restore extension header and change profiles by cryptex values*/
xtn_hdr->length = htons(xtn_hdr_length);
if (xtn_profile_specific == 0xc0de) {
xtn_hdr->profile_specific = htons(0xbede);
} else if (xtn_profile_specific == 0xc2de) {
xtn_hdr->profile_specific = htons(0x1000);
} else {
return srtp_err_status_parse_err;
}
}

if (hdr->x == 1 && session_keys->rtp_xtn_hdr_cipher) {
/*
* extensions header encryption RFC 6904
Expand Down Expand Up @@ -2213,6 +2333,11 @@ srtp_err_status_t srtp_protect(srtp_t ctx,
srtp_stream_ctx_t *stream;
size_t prefix_len;
srtp_session_keys_t *session_keys = NULL;
uint8_t *mki_location = NULL;
int advance_packet_index = 0;
size_t xtn_hdr_length = 0;
int xtn_profile_specific = 0;
uint32_t xtn_hdr_profile_and_value = 0;

debug_print0(mod_srtp, "function srtp_protect");

Expand Down Expand Up @@ -2319,11 +2444,57 @@ srtp_err_status_t srtp_protect(srtp_t ctx,
* 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 any are present.
* If cryptex is in use, the encrypted portion also covers the
* rtp header extension.
*/
enc_start = srtp_get_rtp_hdr_len(hdr);
if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp);
if (stream->rtp_services & sec_serv_conf) {
/* Cryptex can only encrypt CSRCS if header extension is present*/
if (stream->use_cryptex && hdr->cc && !hdr->x) {
return srtp_err_status_parse_err;
}
if (hdr->x == 1) {
xtn_hdr = (srtp_hdr_xtnd_t *)(uint32_t *)hdr +
uint32s_in_rtp_header + hdr->cc;
xtn_hdr_length = ntohs(xtn_hdr->length);
xtn_profile_specific = ntohs(xtn_hdr->profile_specific);
}
/* If no header extension is present cryptex has no effect */
if (stream->use_cryptex && hdr->x) {
/* Change profiles by cryptex values */
if (xtn_profile_specific == 0xbede) {
xtn_hdr_profile_and_value =
htonl(0xc0de << 16 | xtn_hdr_length);
} else if (xtn_profile_specific == 0x1000) {
xtn_hdr_profile_and_value =
htonl(0xc2de << 16 | xtn_hdr_length);
} else {
return srtp_err_status_parse_err;
}
/* Get CSRCs block position or profile if no CSRCs */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Move CSRCS so block is contiguous with extension header block */
for (unsigned char i = hdr->cc; i > 0; --i)
Copy link
Contributor

@paulej paulej Aug 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to do this vs. memcpy() or memmove()? Loops are usually slower, but maybe this doesn't matter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just thought it would be easier to review the change and check it was spec compliant, I can change it to memcpy or memmove if needed

csrcs[i] = csrcs[i - 1];
/* Move profile and length before the CSRCs */
csrcs[0] = xtn_hdr_profile_and_value;
/* Start encrypting in the CSRCS block new position */
enc_start = csrcs + 1;
} else {
enc_start = srtp_get_rtp_hdr_len(hdr);
if (hdr->x == 1) {
enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp);
}
}
/* note: the passed size is without the auth tag */
if (!((uint8_t *)enc_start <= (uint8_t *)hdr + *pkt_octet_len))
return srtp_err_status_parse_err;
enc_octet_len =
(int)(*pkt_octet_len - ((uint8_t *)enc_start - (uint8_t *)hdr));
if (enc_octet_len < 0)
return srtp_err_status_parse_err;
} else {
enc_start = NULL;
}

if (enc_start > rtp_len) {
Expand Down Expand Up @@ -2457,10 +2628,20 @@ srtp_err_status_t srtp_protect(srtp_t ctx,
&enc_octet_len);
if (status) {
return srtp_err_status_cipher_fail;
} else if (rtp != srtp) {
/* if no encryption and not-inplace then need to copy rest of packet */
memcpy(srtp + enc_start, rtp + enc_start, enc_octet_len);
}

/* Restore CSRCs block before sending if using cryptex */
if (stream->use_cryptex && xtn_hdr && hdr->cc) {
/* Restore CSRCS to its original position */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
for (unsigned char i = 0; i < hdr->cc; ++i)
csrcs[i] = csrcs[i + 1];
/* Restore extension header profile and length */
*(uint32_t *)xtn_hdr = xtn_hdr_profile_and_value;
}
} else if (rtp != srtp) {
/* if no encryption and not-inplace then need to copy rest of packet */
memcpy(srtp + enc_start, rtp + enc_start, enc_octet_len);
}

/*
Expand Down Expand Up @@ -2524,6 +2705,10 @@ srtp_err_status_t srtp_unprotect(srtp_t ctx,
bool advance_packet_index = false;
uint32_t roc_to_set = 0;
uint16_t seq_to_set = 0;
size_t xtn_hdr_length = 0;
int xtn_profile_specific = 0;
bool use_cryptex = 0;
uint32_t xtn_hdr_profile_and_value = 0;

debug_print0(mod_srtp, "function srtp_unprotect");

Expand Down Expand Up @@ -2730,6 +2915,51 @@ srtp_err_status_t srtp_unprotect(srtp_t ctx,
}
}

/*
* 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) {
if (hdr->x == 1) {
xtn_hdr = (srtp_hdr_xtnd_t *)(uint32_t *)hdr +
uint32s_in_rtp_header + hdr->cc;
xtn_hdr_length = ntohs(xtn_hdr->length);
xtn_profile_specific = ntohs(xtn_hdr->profile_specific);
}

/* Check if the profile is the one for cryptex */
if (xtn_profile_specific == 0xc0de || xtn_profile_specific == 0xc2de) {
/* Get the 4 bytes of defined by profile and length */
xtn_hdr_profile_and_value = *(uint32_t *)xtn_hdr;
/* Get CSRCs block position or profile if no CSRCs */
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Move CSRCS so block is contiguous with extension header block */
for (unsigned char i = hdr->cc; i > 0; --i)
csrcs[i] = csrcs[i - 1];
/* Move defined by profile before the CSRCs block */
csrcs[0] = xtn_hdr_profile_and_value;
/* Start encrypting in the CSRCS block new position */
enc_start = csrcs + 1;
use_cryptex = 1;
} else {
enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc;
if (hdr->x == 1) {
enc_start += (xtn_hdr_length + 1);
}
}
if (!((uint8_t *)enc_start <=
(uint8_t *)hdr + (*pkt_octet_len - tag_len - mki_size)))
return srtp_err_status_parse_err;
enc_octet_len = (uint32_t)(*pkt_octet_len - tag_len - mki_size -
((uint8_t *)enc_start - (uint8_t *)hdr));
} else {
enc_start = NULL;
}

/*
* 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
Expand Down Expand Up @@ -2765,10 +2995,28 @@ srtp_err_status_t srtp_unprotect(srtp_t ctx,
if (status) {
return srtp_err_status_cipher_fail;
}
if (use_cryptex) {
uint32_t *csrcs = (uint32_t *)hdr + uint32s_in_rtp_header;
/* Restore CSRCS to its original position */
for (unsigned char i = 0; i < hdr->cc; ++i)
csrcs[i] = csrcs[i + 1];
/* Restore extension header and change profiles by cryptex values*/
xtn_hdr->length = htons(xtn_hdr_length);
if (xtn_profile_specific == 0xc0de) {
xtn_hdr->profile_specific = htons(0xbede);
} else if (xtn_profile_specific == 0xc2de) {
xtn_hdr->profile_specific = htons(0x1000);
} else {
return srtp_err_status_parse_err;
}
}
} else if (rtp != srtp) {
/* if no encryption and not-inplace then need to copy rest of packet */
memcpy(rtp + enc_start, srtp + enc_start, enc_octet_len);
}
}




/*
* verify that stream is for received traffic - this check will
Expand Down
Loading
Loading