-
Notifications
You must be signed in to change notification settings - Fork 477
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
base: main
Are you sure you want to change the base?
Changes from 25 commits
9063d2e
95b0e97
62bf7a8
4939886
e16a815
664da14
6fa8d3b
3fe608b
696ae82
4ab5255
ce58dd6
6536373
fbf23e2
f09a939
3f21c3e
5124a97
f8a374b
90d2345
85d291d
ed4b3e3
e84c487
b352f0c
570be3d
cbb0365
34d239e
39bea1d
2ed2ac6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
} | ||
|
||
|
@@ -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; | ||
} | ||
|
@@ -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"); | ||
|
||
|
@@ -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 */ | ||
|
@@ -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); | ||
|
@@ -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"); | ||
|
||
|
@@ -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) { | ||
|
@@ -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 | ||
|
@@ -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"); | ||
|
||
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
@@ -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); | ||
} | ||
|
||
/* | ||
|
@@ -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; | ||
int xtn_hdr_length = 0; | ||
murillo128 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int xtn_profile_specific = 0; | ||
unsigned int use_cryptex = 0; | ||
murillo128 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uint32_t xtn_hdr_profile_and_value = 0; | ||
|
||
debug_print0(mod_srtp, "function srtp_unprotect"); | ||
|
||
|
@@ -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 | ||
|
@@ -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 | ||
|
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.