err_status_t srtp_validate() { unsigned char test_key[30] = { 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39, 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb, 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6 }; uint8_t srtp_plaintext_ref[28] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab }; uint8_t srtp_plaintext[38] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t srtp_ciphertext[38] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c, 0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15, 0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc, 0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb }; srtp_t srtp_snd, srtp_recv; err_status_t status; int len; srtp_policy_t policy; /* * create a session with a single stream using the default srtp * policy and with the SSRC value 0xcafebabe */ crypto_policy_set_rtp_default(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_specific; policy.ssrc.value = 0xcafebabe; policy.key = test_key; policy.next = NULL; status = srtp_create(&srtp_snd, &policy); if (status) return status; /* * protect plaintext, then compare with ciphertext */ len = 28; status = srtp_protect(srtp_snd, srtp_plaintext, &len); if (status || (len != 38)) return err_status_fail; debug_print(mod_driver, "ciphertext:\n %s", octet_string_hex_string(srtp_plaintext, len)); debug_print(mod_driver, "ciphertext reference:\n %s", octet_string_hex_string(srtp_ciphertext, len)); if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) return err_status_fail; /* * create a receiver session context comparable to the one created * above - we need to do this so that the replay checking doesn't * complain */ status = srtp_create(&srtp_recv, &policy); if (status) return status; /* * unprotect ciphertext, then compare with plaintext */ status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) return status; if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) return err_status_fail; return err_status_ok; }
static int start_srtp(struct menc_st *st, const char *suite) { crypto_policy_t policy; err_status_t e; if (0 == str_casecmp(suite, aes_cm_128_hmac_sha1_32)) { crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy); } else if (0 == str_casecmp(suite, aes_cm_128_hmac_sha1_80)) { crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy); } else { DEBUG_WARNING("unknown SRTP crypto suite (%s)\n", suite); return ENOENT; } /* transmit policy */ st->policy_tx.rtp = policy; st->policy_tx.rtcp = policy; st->policy_tx.ssrc.type = ssrc_any_outbound; st->policy_tx.key = st->key_tx; st->policy_tx.next = NULL; /* receive policy */ st->policy_rx.rtp = policy; st->policy_rx.rtcp = policy; st->policy_rx.ssrc.type = ssrc_any_inbound; st->policy_rx.key = st->key_rx; st->policy_rx.next = NULL; /* allocate and initialize the SRTP session */ e = srtp_create(&st->srtp_tx, &st->policy_tx); if (e != err_status_ok) { DEBUG_WARNING("srtp_create TX failed (%H)\n", errstatus_print, e); return EPROTO; } e = srtp_create(&st->srtp_rx, &st->policy_rx); if (err_status_ok != e) { DEBUG_WARNING("srtp_create RX failed (%H)\n", errstatus_print, e); return EPROTO; } /* use SRTP for this stream/session */ st->use_srtp = true; return 0; }
JNIEXPORT jint JNICALL Java_org_theonionphone_protocol_SrtpProtocol_initReceiver (JNIEnv *env, jobject obj, jint ssrc, jbyteArray keyByteArray, jbyteArray saltByteArray) { srtp_policy_t policy; char key[SRTP_KEY_SIZE]; // copy key and salt to an array needed by srtp (*env)->GetByteArrayRegion(env, keyByteArray, 0, KEY_SIZE, key); (*env)->GetByteArrayRegion(env, saltByteArray, 0, SALT_SIZE, key + KEY_SIZE); //set up crypto policies crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_specific; policy.ssrc.value = ssrc; policy.key = (uint8_t *) key; policy.next = NULL; policy.rtp.sec_serv = sec_serv_conf_and_auth; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ //create an srtp stream srtpContextRecv = malloc(sizeof(srtp_t*)); if(srtpContextRecv == NULL) { return 69; } err_status_t status = srtp_create(srtpContextRecv, &policy); return status; }
RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite, bool inbound, const void *key, size_t key_len) { nsresult res = Init(); if (!NS_SUCCEEDED(res)) return NULL; RefPtr<SrtpFlow> flow = new SrtpFlow(); if (!key) { MOZ_MTLOG(PR_LOG_ERROR, "Null SRTP key specified"); return NULL; } if (key_len != SRTP_TOTAL_KEY_LENGTH) { MOZ_MTLOG(PR_LOG_ERROR, "Invalid SRTP key length"); return NULL; } srtp_policy_t policy; memset(&policy, 0, sizeof(srtp_policy_t)); // Note that we set the same cipher suite for RTP and RTCP // since any flow can only have one cipher suite with DTLS-SRTP switch (cipher_suite) { case SRTP_AES128_CM_HMAC_SHA1_80: MOZ_MTLOG(PR_LOG_DEBUG, "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80"); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); break; case SRTP_AES128_CM_HMAC_SHA1_32: MOZ_MTLOG(PR_LOG_DEBUG, "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32"); crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // 80-bit per RFC 5764 break; // S 4.1.2. default: MOZ_MTLOG(PR_LOG_ERROR, "Request to set unknown SRTP cipher suite"); return NULL; } // This key is copied into the srtp_t object, so we don't // need to keep it. policy.key = const_cast<unsigned char *>( static_cast<const unsigned char *>(key)); policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound; policy.ssrc.value = 0; policy.ekt = NULL; policy.window_size = 0; // Use the default value. policy.allow_repeat_tx = 0; // TODO([email protected]): revisit? policy.next = NULL; // Now make the session err_status_t r = srtp_create(&flow->session_, &policy); if (r != err_status_ok) { MOZ_MTLOG(PR_LOG_ERROR, "Error creating srtp session"); return NULL; } return flow; }
bool SrtpChannel::configureSrtpSession(srtp_t *session, const char* key, enum TransmissionType type) { srtp_policy_t policy; memset(&policy, 0, sizeof(policy)); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); if (type == SENDING) { policy.ssrc.type = ssrc_any_outbound; } else { policy.ssrc.type = ssrc_any_inbound; } policy.ssrc.value = 0; policy.window_size = 1024; policy.allow_repeat_tx = 1; policy.next = NULL; //ELOG_DEBUG("auth_tag_len %d", policy.rtp.auth_tag_len); gsize len = 0; uint8_t *akey = (uint8_t*) g_base64_decode((gchar*) key, &len); ELOG_DEBUG("set master key/salt to %s/", octet_string_hex_string(akey, 16)); // allocate and initialize the SRTP session policy.key = akey; int res = srtp_create(session, &policy); if (res!=0){ ELOG_ERROR("Failed to create srtp session with %s, %d", octet_string_hex_string(akey, 16), res); } return res!=0? false:true; }
double srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy) { srtp_t srtp; srtp_hdr_t *mesg; int i; clock_t timer; int num_trials = 100000; int len; uint32_t ssrc; err_status_t status; /* * allocate and initialize an srtp session */ status = srtp_create(&srtp, policy); if (status) { printf("error: srtp_create() failed with error code %d\n", status); exit(1); } /* * if the ssrc is unspecified, use a predetermined one */ if (policy->ssrc.type != ssrc_specific) { ssrc = 0xdeadbeef; } else { ssrc = policy->ssrc.value; } /* * create a test packet */ mesg = srtp_create_test_packet(msg_len_octets, ssrc); if (mesg == NULL) return 0.0; /* indicate failure by returning zero */ timer = clock(); for (i=0; i < num_trials; i++) { err_status_t status; len = msg_len_octets + 12; /* add in rtp header length */ /* srtp protect message */ status = srtp_protect(srtp, mesg, &len); if (status) { printf("error: srtp_protect() failed with error code %d\n", status); exit(1); } /* increment message number */ mesg->seq = htons(ntohs(mesg->seq) + 1); } timer = clock() - timer; free(mesg); return (double) (msg_len_octets) * 8 * num_trials * CLOCKS_PER_SEC / timer; }
trtp_srtp_set_crypto(struct trtp_manager_s* rtp_mgr, const char* crypto_line, int32_t idx) { //e.g. 2 F8_128_HMAC_SHA1_80 inline:MTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5QUJjZGVm|2^20|1:4;inline:QUJjZGVmMTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5|2^20|2:4" trtp_srtp_ctx_xt* srtp_ctx; int ret; uint8_t *key_bin; err_status_t srtp_err; int32_t tag, crypto_type; char key_str[SRTP_MAX_KEY_LEN + 1]; memset(key_str, 0, sizeof(key_str)); if((ret = trtp_srtp_match_line(crypto_line, &tag, &crypto_type, key_str, sizeof(key_str) - 1))){ return ret; } srtp_ctx = &rtp_mgr->srtp_contexts[idx][crypto_type]; ret = trtp_srtp_ctx_deinit(srtp_ctx); srtp_ctx->tag = tag; srtp_ctx->crypto_type = (trtp_srtp_crypto_type_t)crypto_type; memcpy(srtp_ctx->key_str, key_str, sizeof(srtp_ctx->key_str)); switch(srtp_ctx->crypto_type){ case HMAC_SHA1_80: { crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); if(idx == TRTP_SRTP_LINE_IDX_REMOTE){ trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32]); rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].tag = srtp_ctx->tag; } break; } case HMAC_SHA1_32: { crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); // RTCP always 80 if(idx == TRTP_SRTP_LINE_IDX_REMOTE){ trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]); rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].tag = srtp_ctx->tag; } break; } } key_bin = (unsigned char*)srtp_ctx->key_bin; tsk_base64_decode((const uint8_t*)srtp_ctx->key_str, tsk_strlen(srtp_ctx->key_str), (char**)&key_bin); srtp_ctx->policy.key = key_bin; srtp_ctx->policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound; if((srtp_err = srtp_create(&srtp_ctx->session, &srtp_ctx->policy)) != err_status_ok){ TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err); return -3; } srtp_ctx->initialized = tsk_true; return 0; }
void * sender_thread (void *arg) { err_status_t status; thread_parms_t *tp = (thread_parms_t*)arg; rtp_sender_t snd[NUM_SSRC_PER_THREAD]; int cnt = 0; int i; srtp_ctx_t *srtp_ctx = NULL; printf("\nStarting sender thread (port: %d base-ssrc: %x stream_cnt: %d)\n", tp->port, tp->ssrc, tp->stream_cnt); /* initialize sender's rtp and srtp contexts */ status = srtp_create(&srtp_ctx, tp->policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* now add the streams on the session */ for (i = 0; i < tp->stream_cnt; i++) { rtp_sender_init(&snd[i], tp->sock, tp->name, tp->ssrc); snd[i].srtp_ctx = srtp_ctx; status = srtp_add_stream(snd[i].srtp_ctx, tp->policy); if (status) { fprintf(stderr, "error: srtp_add_stream() failed with code %d\n", status); exit(1); } tp->policy->ssrc.value++; tp->ssrc++; } while (cnt < THREAD_PKT_CNT) { for (i = 0; i < tp->stream_cnt; i++) { rtp_sendto(&snd[i], test_data, DATA_LEN); cnt++; if (cnt % STAT_WINDOW == 0) { printf("Thread id %d transmit count is %d\n", tp->thread_num, cnt); } } usleep(SLEEP_LEN); } /* * Clean up the session */ srtp_dealloc(srtp_ctx); return NULL; }
int trtp_srtp_set_key_and_salt(trtp_manager_t* rtp_mgr, trtp_srtp_crypto_type_t crypto_type, const void* key, tsk_size_t key_size, const void* salt, tsk_size_t salt_size, int32_t idx) { int ret; trtp_srtp_ctx_xt* srtp_ctx; err_status_t srtp_err; if(!rtp_mgr || !key || !key_size || !salt || !salt_size){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if((key_size + salt_size) > sizeof(srtp_ctx->key_bin)){ TSK_DEBUG_ERROR("Invalid [key||salt].len [%u||%u]", key_size, salt_size); } srtp_ctx = &rtp_mgr->srtp_contexts[idx][0]; if((ret = trtp_srtp_ctx_deinit(srtp_ctx))){ return ret; } switch((srtp_ctx->crypto_type = crypto_type)){ case HMAC_SHA1_80: default: { crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); break; } case HMAC_SHA1_32: { crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); // always 80 break; } } memcpy(srtp_ctx->key_bin, key, key_size); #if HAVE_APPEND_SALT_TO_KEY append_salt_to_key(srtp_ctx->key_bin, key_size, (void*)salt, salt_size); #else memcpy(&srtp_ctx->key_bin[key_size], salt, salt_size); #endif srtp_ctx->policy.key = srtp_ctx->key_bin; srtp_ctx->policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound; if((srtp_err = srtp_create(&srtp_ctx->session, &srtp_ctx->policy)) != err_status_ok){ TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err); return -3; } srtp_ctx->initialized = tsk_true; return 0; }
int trtp_srtp_ctx_init(trtp_srtp_ctx_xt* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc){ char* key_str = ctx->key_str; err_status_t srtp_err; tsk_size_t size; if(!ctx){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(ctx->initialized){ trtp_srtp_ctx_deinit(ctx); } ctx->tag = tag; ctx->crypto_type = type; if((srtp_err = crypto_get_random((unsigned char*)ctx->key_bin, sizeof(ctx->key_bin))) != err_status_ok){ TSK_DEBUG_ERROR("crypto_get_random() failed"); return -2; } size = tsk_base64_encode((const uint8_t*)ctx->key_bin, sizeof(ctx->key_bin), &key_str); key_str[size] = '\0'; switch(ctx->crypto_type){ case HMAC_SHA1_80: { crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); break; } case HMAC_SHA1_32: default: { crypto_policy_set_aes_cm_128_hmac_sha1_32(&ctx->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); // RTCP always 80 break; } } ctx->policy.key = (unsigned char*)ctx->key_bin; ctx->policy.ssrc.type = ssrc_any_outbound; ctx->policy.ssrc.value = ssrc; if((srtp_err = srtp_create(&ctx->session, &ctx->policy)) != err_status_ok){ TSK_DEBUG_ERROR("srtp_create() failed"); return -3; } ctx->initialized = tsk_true; return 0; }
err_status_t srtp_print_policy(const srtp_policy_t *policy) { err_status_t status; srtp_t session; status = srtp_create(&session, policy); if (status) return status; status = srtp_session_print_policy(session); if (status) return status; status = srtp_dealloc(session); if (status) return status; return err_status_ok; }
JNIEXPORT jint JNICALL Java_org_theonionphone_protocol_SrtpProtocol_initSender (JNIEnv *env, jobject obj, jbyteArray keyByteArray, jbyteArray saltByteArray, jint codecType, jint sampleCount, jint payloadSizeInBytes, jint rtpPacketSizeInBytes, jint srtpPacketSizeInBytes) { srtp_policy_t policy; char key[SRTP_KEY_SIZE]; payloadSize = payloadSizeInBytes; rtpPacketSize = rtpPacketSizeInBytes; srtpPacketSize = srtpPacketSizeInBytes; // copy key and salt to an array needed by srtp (*env)->GetByteArrayRegion(env, keyByteArray, 0, KEY_SIZE, key); (*env)->GetByteArrayRegion(env, saltByteArray, 0, SALT_SIZE, key + KEY_SIZE); //initialize rtp err_status_t status = initRtp(&rtpContext, codecType, sampleCount); if(status) { return status; } //initialize srtp status = srtp_init(); if(status) { return status; } //set up crypto policies crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_specific; policy.ssrc.value = rtpContext->mSsrc; policy.key = (uint8_t *) key; policy.next = NULL; policy.rtp.sec_serv = sec_serv_conf_and_auth; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ //create an srtp stream srtpContextSend = malloc(sizeof(srtp_t*)); if(srtpContextSend == NULL) { return 69; } status = srtp_create(srtpContextSend, &policy); return status; }
err_status_t srtp_test_remove_stream() { err_status_t status; srtp_policy_t *policy_list; srtp_t session; srtp_stream_t stream; /* * srtp_get_stream() is a libSRTP internal function that we declare * here so that we can use it to verify the correct operation of the * library */ extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc); status = srtp_create_big_policy(&policy_list); if (status) return status; status = srtp_create(&session, policy_list); if (status) return status; /* * check for false positives by trying to remove a stream that's not * in the session */ status = srtp_remove_stream(session, htonl(0xaaaaaaaa)); if (status != err_status_no_ctx) return err_status_fail; /* * check for false negatives by removing stream 0x1, then * searching for streams 0x0 and 0x2 */ status = srtp_remove_stream(session, htonl(0x1)); if (status != err_status_ok) return err_status_fail; stream = srtp_get_stream(session, htonl(0x0)); if (stream == NULL) return err_status_fail; stream = srtp_get_stream(session, htonl(0x2)); if (stream == NULL) return err_status_fail; return err_status_ok; }
srtpw_err_status_t srtpw_srtp_create(srtpw_srtp **srtp, srtpw_srtp_policy *srtp_policy) { int status=0; /* * create a session with a single stream using the default srtp * policy and with the SSRC value 0xcafebabe */ srtp_policy_t *policy =(srtp_policy_t *)srtp_policy; srtpw_log(err_level_info, "srtpw_srtp_create: policy:0x%x",policy); #if 0 crypto_policy_set_rtp_default(&policy->rtp); crypto_policy_set_rtcp_default(&policy->rtcp); policy->ssrc.type = ssrc_specific; policy->ssrc.value = 0; policy->key = NULL; #endif policy->next = NULL; status = srtp_create((srtp_t *)srtp,policy); return status; }
double srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy) { srtp_ctx_t *srtp; srtp_hdr_t *mesg; int i; int len; clock_t timer; int num_trials = 1000000; uint32_t ssrc = policy->ssrc.value; err_status_t status; /* * allocate and initialize an srtp session */ status = srtp_create(&srtp, policy); if (status) { printf("error: srtp_create() failed with error code %d\n", status); exit(1); } mesg = srtp_create_test_packet(msg_len_octets, ssrc); if (mesg == NULL) return 0.0; /* indicate failure by returning zero */ len = msg_len_octets; srtp_protect(srtp, (srtp_hdr_t *)mesg, &len); timer = clock(); for (i=0; i < num_trials; i++) { len = msg_len_octets; srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len); } timer = clock() - timer; free(mesg); return (double) num_trials * CLOCKS_PER_SEC / timer; }
RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite, bool inbound, const void *key, size_t key_len) { nsresult res = Init(); if (!NS_SUCCEEDED(res)) return nullptr; RefPtr<SrtpFlow> flow = new SrtpFlow(); if (!key) { CSFLogError(LOGTAG, "Null SRTP key specified"); return nullptr; } if (key_len != SRTP_TOTAL_KEY_LENGTH) { CSFLogError(LOGTAG, "Invalid SRTP key length"); return nullptr; } srtp_policy_t policy; memset(&policy, 0, sizeof(srtp_policy_t)); // Note that we set the same cipher suite for RTP and RTCP // since any flow can only have one cipher suite with DTLS-SRTP switch (cipher_suite) { case SRTP_AES128_CM_HMAC_SHA1_80: CSFLogDebug(LOGTAG, "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80"); srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); break; case SRTP_AES128_CM_HMAC_SHA1_32: CSFLogDebug(LOGTAG, "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32"); srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // 80-bit per RFC 5764 break; // S 4.1.2. default: CSFLogError(LOGTAG, "Request to set unknown SRTP cipher suite"); return nullptr; } // This key is copied into the srtp_t object, so we don't // need to keep it. policy.key = const_cast<unsigned char *>( static_cast<const unsigned char *>(key)); policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound; policy.ssrc.value = 0; policy.ekt = nullptr; policy.window_size = 1024; // Use the Chrome value. Needs to be revisited. Default is 128 policy.allow_repeat_tx = 1; // Use Chrome value; needed for NACK mode to work policy.next = nullptr; // Now make the session srtp_err_status_t r = srtp_create(&flow->session_, &policy); if (r != srtp_err_status_ok) { CSFLogError(LOGTAG, "Error creating srtp session"); return nullptr; } return flow; }
int main (int argc, char *argv[]) { struct rtp *session; int rx_port, tx_port, fd; uint32_t read_size, packet_size, number_of_packet; uint8_t buff[BUFFSIZE]; off_t cur_pos; char *ip_addr; char filename[1024]; int c; struct hostent *h; struct utsname myname; #ifdef HAVE_SRTP #else void *srtp_data; #endif unsigned int extra_len; int do_auth = 1, do_encrypt = 1; ssize_t readit; ssize_t sendit; int do_rtcp = false; // Setting of default session if(uname(&myname) < 0){ fprintf(stderr,"uname\n"); exit(1); } if((h = gethostbyname(myname.nodename)) == NULL) { herror("gethostbyname"); exit(1); } ip_addr = strdup(inet_ntoa(*((struct in_addr *)h->h_addr))); rx_port = 15002; tx_port = 15000; // Option opterr = 0; while((c = getopt(argc, argv, "acdehi:r:t:f:")) != -1){ switch (c) { case 'a': do_auth = 0; break; case 'c': do_rtcp = 1; break; case 'd': dump_pak = true; break; case 'e': do_encrypt = 0; break; case 'h': printf("Usage: ./test_rtp_client -i <IP_Addr> -r <rx_port> -t <tx_port> -f <filename>\n"); printf("Default values are as follows...\n"); printf("ip_addr = %s\n", ip_addr); printf("rx_port = %d\n", rx_port); printf("tx_port = %d\n", tx_port); printf("Filename = %s\n", filename); exit(-1); case 'i': strcpy(ip_addr, optarg); break; case 'r': rx_port = atoi(optarg); break; case 't': tx_port = atoi(optarg); break; case 'f': strcpy(filename,optarg); break; case '?': printf("usage: ./test_rtp_client -i <IP_Addr> -r <rx_port> -t <tx_port> -f <filename>\n"); exit(1); } } if (optind < argc) { for(; optind < argc; optind++) { printf("error->%s(#%d): put -[i|r|t|f] \n", argv[optind],optind-1); } exit(1); } // display session information printf("\n-Session Information-\n"); printf(" ip_addr = %s\n", ip_addr); printf(" rx_port = %d\n", rx_port); printf(" tx_port = %d\n", tx_port); printf(" filename = %s\n", filename); printf("Press Return key..."); // getchar(); // Open Original File to compare with received file if((fd = open(filename, O_RDONLY)) == -1){ perror(filename); exit(1); } rtp_stream_params_t rsp; rtp_default_params(&rsp); rsp.rtp_addr = ip_addr; rsp.rtp_rx_port = rx_port; rsp.rtp_tx_port = tx_port; rsp.rtp_ttl = TTL; rsp.rtcp_bandwidth = RTCP_BW; rsp.rtp_callback = c_rtp_callback; rsp.transmit_initial_rtcp = 1; if ( (session = rtp_init_stream(&rsp) ) == NULL){ exit(-1); } rtp_set_my_ssrc(session,OUR_SSRC); #ifdef HAVE_SRTP /////////// start will //set NULL security services //uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ srtp_policy_t policy; char key[64]; char keystr[128]; uint ix; #if 1 strcpy(keystr, "c1eec3717da76195bb878578790af71c4ee9f859e197a414a78d5abc7451"); hex_string_to_octet_string(key, keystr, 60); #else memset(key, 0, sizeof(key)); #endif for (ix = 0; ix < 30; ix++) { printf("%02x ", key[ix]); } printf("\n"); #if 0 // NULL cipher policy.key = (uint8_t *) key; policy.ssrc.type = ssrc_any_outbound; //ssrc_specific; policy.ssrc.value = 0x96;//OUR_SSRC; policy.rtp.cipher_type = NULL_CIPHER; policy.rtp.cipher_key_len = 0; policy.rtp.auth_type = NULL_AUTH; policy.rtp.auth_key_len = 0; policy.rtp.auth_tag_len = 0; policy.rtp.sec_serv = sec_serv_none; policy.rtcp.cipher_type = NULL_CIPHER; policy.rtcp.cipher_key_len = 0; policy.rtcp.auth_type = NULL_AUTH; policy.rtcp.auth_key_len = 0; policy.rtcp.auth_tag_len = 0; policy.rtcp.sec_serv = sec_serv_none; policy.next = NULL; #else //confidentiality only, no auth crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_any_outbound; policy.key = (uint8_t *) key; policy.next = NULL; policy.rtp.sec_serv = sec_serv_conf;//sec_servs; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ #endif err_status_t status; printf("ABOUT TO SRTP_INIT\n"); status = srtp_init(); if (status) { printf("error: srtp initialization failed with error code %d\n", status); exit(1); } printf("ABOUT TO SRTP_CREAT\n"); srtp_ctx_t *srtp_ctx = NULL; status = srtp_create(&srtp_ctx, &policy); if (status) { printf("error: srtp_create() failed with code %d\n", status); exit(1); } printf("DONE WITH SRTP_CREATE\n"); extra_len = 0; #else extra_len = 0; srtp_data = NULL; #endif rtp_encryption_params_t params; params.rtp_encrypt = ENCRYPT_FUNCTION; params.rtcp_encrypt = RTCP_ENCRYPT_FUNCTION; params.rtp_decrypt = DECRYPT_FUNCTION; params.rtcp_decrypt = RTCP_DECRYPT_FUNCTION; params.userdata = srtp_data; params.rtp_auth_alloc_extra = params.rtcp_auth_alloc_extra = 0; rtp_set_encryption_params(session, ¶ms); if (do_rtcp) { rtcp_file = fopen("server.rtcp", FOPEN_WRITE_BINARY); } cur_pos = 0; packet_size = 64; number_of_packet = 0; while(1) { // change BUFFSIZE to be an incrementing value from 64 to 1450 if(packet_size > 1450) packet_size = 725; readit = read(fd, buff, packet_size); if (readit < 0) { perror("file read"); exit(1); } read_size = readit; //int buflen = readit; if (read_size == 0) break; //printf("about to protect\n"); #if 0 sendit = rtp_send_data(session, cur_pos, 97,//pt 0,//m 0,//cc NULL, //csrc[], buff,//data read_size,//data_len NULL,//*extn 0, 0); #else { struct iovec iov[2]; iov[0].iov_len = read_size % 48; if (iov[0].iov_len == 0) iov[0].iov_len = 1; iov[0].iov_base = buff; iov[1].iov_len = read_size - iov[0].iov_len; iov[1].iov_base = buff + iov[0].iov_len; sendit = rtp_send_data_iov(session, cur_pos, 97, 0, 0, NULL, iov, read_size > iov[0].iov_len ? 2 : 1, NULL, 0, 0, 0); } #endif if (sendit < 0) { printf("rtp_send_data error\n"); exit(1); } if (do_rtcp) rtp_send_ctrl(session, cur_pos, NULL); printf("set timestamp = "U64", size %u\n", cur_pos, read_size); cur_pos += read_size; packet_size++; number_of_packet++; //rtp_periodic(); //rtp_send_ctrl(session,cur_pos,NULL); rtp_update(session); // Some sort of sleep here... usleep(2 * 1000); } printf("I've sent %d RTP packets!\n\n", number_of_packet); close(fd); if (rtcp_file != NULL) fclose(rtcp_file); rtp_done(session); return 0; }
/** * SRTP crypto data ready for the sender or receiver. * * The ZRTP implementation calls this method right after all SRTP * secrets are computed and ready to be used. The parameter points * to a structure that contains pointers to the SRTP secrets and a * <code>enum Role</code>. The called method (the implementation * of this abstract method) must either copy the pointers to the SRTP * data or the SRTP data itself to a save place. The SrtpSecret_t * structure is destroyed after the callback method returns to the * ZRTP implementation. * * The SRTP data themselves are obtained in the ZRtp object and are * valid as long as the ZRtp object is active. TheZRtp's * destructor clears the secrets. Thus the called method needs to * save the pointers only, ZRtp takes care of the data. * * The implementing class may enable SRTP processing in this * method or delay it to srtpSecertsOn(). * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param secrets A pointer to a SrtpSecret_t structure that * contains all necessary data. * * @param part for which part (Sender or Receiver) this data is * valid. * * @return Returns false if something went wrong during * initialization of SRTP context, for example memory shortage. */ static int32_t ozrtp_srtpSecretsReady (ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part ) { srtp_policy_t policy; err_status_t srtpCreateStatus; err_status_t addStreamStatus; OrtpZrtpContext *userData = user_data(ctx); ortp_message("ZRTP secrets for %s are ready; auth tag len is %i", (part == ForSender) ? "sender" : "receiver",secrets->srtpAuthTagLen); // Get authentication and cipher algorithms in srtp format if (secrets->authAlgorithm != zrtp_Sha1) { ortp_fatal("unsupported authentication algorithm by srtp"); } if (secrets->symEncAlgorithm != zrtp_Aes) { ortp_fatal("unsupported cipher algorithm by srtp"); } /* * Don't use crypto_policy_set_from_profile_for_rtp(), it is totally buggy. */ memset(&policy,0,sizeof(policy)); if (secrets->srtpAuthTagLen == 32){ crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtcp); }else if (secrets->srtpAuthTagLen == 80){ crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); }else{ ortp_fatal("unsupported auth tag len"); } if (part == ForSender) { srtpCreateStatus=srtp_create(&userData->srtpSend, NULL); policy.ssrc.type=ssrc_specific; policy.ssrc.value=userData->session->snd.ssrc; // us policy.key=key_with_salt(secrets, secrets->role); addStreamStatus=srtp_add_stream(userData->srtpSend, &policy); } else { //if (part == ForReceiver) srtpCreateStatus=srtp_create(&userData->srtpRecv, NULL); policy.ssrc.type = ssrc_any_inbound; /*we don't know the incoming ssrc will be */ int32_t peerRole=secrets->role == Initiator ? Responder : Initiator; policy.key=key_with_salt(secrets,peerRole); addStreamStatus=srtp_add_stream(userData->srtpRecv, &policy); } ortp_free(policy.key); if (srtpCreateStatus != err_status_ok) { ortp_error("ZRTP Error %u during creation of SRTP context for %s", srtpCreateStatus, (part == ForSender) ? "sender" : "receiver"); return 0; } if (addStreamStatus != err_status_ok) { ortp_error("ZRTP Error %u during addition of SRTP stream for %s", addStreamStatus, (part == ForSender) ? "sender" : "receiver"); return 0; } return 1; }
void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len) { if(dtls == NULL) { JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n"); return; } janus_ice_component *component = (janus_ice_component *)dtls->component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return; } if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) { JANUS_LOG(LOG_WARN, "[%"SCNu64"] Alert already triggered, clearing up...\n", handle->handle_id); return; } if(!dtls->ssl || !dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); return; } janus_dtls_fd_bridge(dtls); int written = BIO_write(dtls->read_bio, buf, len); JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Written %d of those bytes on the read BIO...\n", handle->handle_id, written); janus_dtls_fd_bridge(dtls); /* Try to read data */ char data[1500]; /* FIXME */ memset(&data, 0, 1500); int read = SSL_read(dtls->ssl, &data, 1500); JANUS_LOG(LOG_HUGE, "[%"SCNu64"] ... and read %d of them from SSL...\n", handle->handle_id, read); if(read < 0) { unsigned long err = SSL_get_error(dtls->ssl, read); if(err == SSL_ERROR_SSL) { /* Ops, something went wrong with the DTLS handshake */ char error[200]; ERR_error_string_n(ERR_get_error(), error, 200); JANUS_LOG(LOG_ERR, "[%"SCNu64"] Handshake error: %s\n", handle->handle_id, error); return; } } janus_dtls_fd_bridge(dtls); if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) { /* DTLS alert triggered, we should end it here */ JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id); return; } if(!SSL_is_init_finished(dtls->ssl)) { /* Nothing else to do for now */ JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Initialization not finished yet...\n", handle->handle_id); return; } if(dtls->ready) { /* There's data to be read? */ JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Any data available?\n", handle->handle_id); #ifdef HAVE_SCTP if(dtls->sctp != NULL && read > 0) { JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Sending data (%d bytes) to the SCTP stack...\n", handle->handle_id, read); janus_sctp_data_from_dtls(dtls->sctp, data, read); } #else if(read > 0) { JANUS_LOG(LOG_WARN, "[%"SCNu64"] Data available but Data Channels support disabled...\n", handle->handle_id); } #endif } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS established, yay!\n", handle->handle_id); /* Check the remote fingerprint */ X509 *rcert = SSL_get_peer_certificate(dtls->ssl); if(!rcert) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote certificate??\n", handle->handle_id); } else { unsigned int rsize; unsigned char rfingerprint[EVP_MAX_MD_SIZE]; char remote_fingerprint[160]; char *rfp = (char *)&remote_fingerprint; if(handle->remote_hashing && !strcasecmp(handle->remote_hashing, "sha-1")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id); X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize); } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-256 fingerprint of remote certificate...\n", handle->handle_id); X509_digest(rcert, EVP_sha256(), (unsigned char *)rfingerprint, &rsize); } X509_free(rcert); rcert = NULL; unsigned int i = 0; for(i = 0; i < rsize; i++) { g_snprintf(rfp, 4, "%.2X:", rfingerprint[i]); rfp += 3; } *(rfp-1) = 0; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n", handle->handle_id, handle->remote_hashing ? handle->remote_hashing : "sha-256", remote_fingerprint); if(!strcasecmp(remote_fingerprint, handle->remote_fingerprint ? handle->remote_fingerprint : "(none)")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Fingerprint is a match!\n", handle->handle_id); dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED; dtls->dtls_connected = janus_get_monotonic_time(); } else { /* FIXME NOT a match! MITM? */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Fingerprint is NOT a match! got %s, expected %s\n", handle->handle_id, remote_fingerprint, handle->remote_fingerprint); dtls->dtls_state = JANUS_DTLS_STATE_FAILED; goto done; } if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) { if(component->stream_id == handle->audio_id || component->stream_id == handle->video_id) { /* Complete with SRTP setup */ unsigned char material[SRTP_MASTER_LENGTH*2]; unsigned char *local_key, *local_salt, *remote_key, *remote_salt; /* Export keying material for SRTP */ if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LENGTH*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { /* Oops... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); goto done; } /* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */ if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) { local_key = material; remote_key = local_key + SRTP_MASTER_KEY_LENGTH; local_salt = remote_key + SRTP_MASTER_KEY_LENGTH; remote_salt = local_salt + SRTP_MASTER_SALT_LENGTH; } else { remote_key = material; local_key = remote_key + SRTP_MASTER_KEY_LENGTH; remote_salt = local_key + SRTP_MASTER_KEY_LENGTH; local_salt = remote_salt + SRTP_MASTER_SALT_LENGTH; } /* Build master keys and set SRTP policies */ /* Remote (inbound) */ crypto_policy_set_rtp_default(&(dtls->remote_policy.rtp)); crypto_policy_set_rtcp_default(&(dtls->remote_policy.rtcp)); dtls->remote_policy.ssrc.type = ssrc_any_inbound; unsigned char remote_policy_key[SRTP_MASTER_LENGTH]; dtls->remote_policy.key = (unsigned char *)&remote_policy_key; memcpy(dtls->remote_policy.key, remote_key, SRTP_MASTER_KEY_LENGTH); memcpy(dtls->remote_policy.key + SRTP_MASTER_KEY_LENGTH, remote_salt, SRTP_MASTER_SALT_LENGTH); #if HAS_DTLS_WINDOW_SIZE dtls->remote_policy.window_size = 128; dtls->remote_policy.allow_repeat_tx = 0; #endif dtls->remote_policy.next = NULL; /* Local (outbound) */ crypto_policy_set_rtp_default(&(dtls->local_policy.rtp)); crypto_policy_set_rtcp_default(&(dtls->local_policy.rtcp)); dtls->local_policy.ssrc.type = ssrc_any_outbound; unsigned char local_policy_key[SRTP_MASTER_LENGTH]; dtls->local_policy.key = (unsigned char *)&local_policy_key; memcpy(dtls->local_policy.key, local_key, SRTP_MASTER_KEY_LENGTH); memcpy(dtls->local_policy.key + SRTP_MASTER_KEY_LENGTH, local_salt, SRTP_MASTER_SALT_LENGTH); #if HAS_DTLS_WINDOW_SIZE dtls->local_policy.window_size = 128; dtls->local_policy.allow_repeat_tx = 0; #endif dtls->local_policy.next = NULL; /* Create SRTP sessions */ err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy)); if(res != err_status_ok) { /* Something went wrong... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res)); goto done; } JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy)); if(res != err_status_ok) { /* Something went wrong... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res)); goto done; } dtls->srtp_valid = 1; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); } #ifdef HAVE_SCTP if(component->stream_id == handle->data_id || (janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS))) { /* FIXME Create SCTP association as well (5000 should be dynamic, from the SDP...) */ dtls->sctp = janus_sctp_association_create(dtls, handle->handle_id, 5000); if(dtls->sctp != NULL) { /* FIXME We need to start it in a thread, though, since it has blocking accept/connect stuff */ GError *error = NULL; g_thread_try_new("DTLS-SCTP", janus_dtls_sctp_setup_thread, dtls, &error); if(error != NULL) { /* Something went wrong... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got error %d (%s) trying to launch the DTLS-SCTP thread...\n", handle->handle_id, error->code, error->message ? error->message : "??"); } dtls->srtp_valid = 1; } } #endif dtls->ready = 1; } done: if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) { /* Handshake successfully completed */ janus_ice_dtls_handshake_done(handle, component); } else { /* Something went wrong in either DTLS or SRTP... tell the plugin about it */ janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0); janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING); } } } }
err_status_t srtcp_test(const srtp_policy_t *policy) { int i; srtp_t srtcp_sender; srtp_t srtcp_rcvr; err_status_t status = err_status_ok; srtp_hdr_t *hdr, *hdr2; uint8_t hdr_enc[64]; uint8_t *pkt_end; int msg_len_octets, msg_len_enc; int len; int tag_length = policy->rtp.auth_tag_len; uint32_t ssrc; srtp_policy_t *rcvr_policy; err_check(srtp_create(&srtcp_sender, policy)); /* print out policy */ err_check(srtp_session_print_policy(srtcp_sender)); /* * initialize data buffer, using the ssrc in the policy unless that * value is a wildcard, in which case we'll just use an arbitrary * one */ if (policy->ssrc.type != ssrc_specific) ssrc = 0xdecafbad; else ssrc = policy->ssrc.value; msg_len_octets = 28; hdr = srtp_create_test_packet(msg_len_octets, ssrc); if (hdr == NULL) return err_status_alloc_fail; hdr2 = srtp_create_test_packet(msg_len_octets, ssrc); if (hdr2 == NULL) { free(hdr); return err_status_alloc_fail; } /* set message length */ len = msg_len_octets; debug_print(mod_driver, "before protection:\n%s", srtp_packet_to_string(hdr, len)); #if PRINT_REFERENCE_PACKET debug_print(mod_driver, "reference packet before protection:\n%s", octet_string_hex_string((uint8_t *)hdr, len)); #endif err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len)); debug_print(mod_driver, "after protection:\n%s", srtp_packet_to_string(hdr, len)); #if PRINT_REFERENCE_PACKET debug_print(mod_driver, "after protection:\n%s", octet_string_hex_string((uint8_t *)hdr, len)); #endif /* save protected message and length */ memcpy(hdr_enc, hdr, len); msg_len_enc = len; /* * check for overrun of the srtp_protect() function * * The packet is followed by a value of 0xfffff; if the value of the * data following the packet is different, then we know that the * protect function is overwriting the end of the packet. */ pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t) + msg_len_octets + tag_length; for (i = 0; i < 4; i++) if (pkt_end[i] != 0xff) { fprintf(stdout, "overwrite in srtp_protect_rtcp() function " "(expected %x, found %x in trailing octet %d)\n", 0xff, ((uint8_t *)hdr)[i], i); free(hdr); free(hdr2); return err_status_algo_fail; } /* * if the policy includes confidentiality, check that ciphertext is * different than plaintext * * Note that this check will give false negatives, with some small * probability, especially if the packets are short. For that * reason, we skip this check if the plaintext is less than four * octets long. */ if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) { printf("testing that ciphertext is distinct from plaintext..."); status = err_status_algo_fail; for (i=12; i < msg_len_octets+12; i++) if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) { status = err_status_ok; } if (status) { printf("failed\n"); free(hdr); free(hdr2); return status; } printf("passed\n"); } /* * if the policy uses a 'wildcard' ssrc, then we need to make a copy * of the policy that changes the direction to inbound * * we always copy the policy into the rcvr_policy, since otherwise * the compiler would fret about the constness of the policy */ rcvr_policy = malloc(sizeof(srtp_policy_t)); if (rcvr_policy == NULL) return err_status_alloc_fail; memcpy(rcvr_policy, policy, sizeof(srtp_policy_t)); if (policy->ssrc.type == ssrc_any_outbound) { rcvr_policy->ssrc.type = ssrc_any_inbound; } err_check(srtp_create(&srtcp_rcvr, rcvr_policy)); err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len)); debug_print(mod_driver, "after unprotection:\n%s", srtp_packet_to_string(hdr, len)); /* verify that the unprotected packet matches the origial one */ for (i=0; i < msg_len_octets; i++) if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) { fprintf(stdout, "mismatch at octet %d\n", i); status = err_status_algo_fail; } if (status) { free(hdr); free(hdr2); return status; } /* * if the policy includes authentication, then test for false positives */ if (policy->rtp.sec_serv & sec_serv_auth) { char *data = ((char *)hdr) + 12; printf("testing for false positives in replay check..."); /* set message length */ len = msg_len_enc; /* unprotect a second time - should fail with a replay error */ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len); if (status != err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); free(hdr2); return status; } else { printf("passed\n"); } printf("testing for false positives in auth check..."); /* increment sequence number in header */ hdr->seq++; /* set message length */ len = msg_len_octets; /* apply protection */ err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len)); /* flip bits in packet */ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len); if (status != err_status_auth_fail) { printf("failed\n"); free(hdr); free(hdr2); return status; } else { printf("passed\n"); } } err_check(srtp_dealloc(srtcp_sender)); err_check(srtp_dealloc(srtcp_rcvr)); free(hdr); free(hdr2); return err_status_ok; }
/* Create a stream in the session */ static err_status_t init_session_stream (GstSrtpDec * filter, guint32 ssrc, GstSrtpDecSsrcStream * stream) { err_status_t ret; srtp_policy_t policy; GstMapInfo map; guchar tmp[1]; memset (&policy, 0, sizeof (srtp_policy_t)); if (!stream) return err_status_bad_param; GST_INFO_OBJECT (filter, "Setting RTP policy..."); set_crypto_policy_cipher_auth (stream->rtp_cipher, stream->rtp_auth, &policy.rtp); GST_INFO_OBJECT (filter, "Setting RTCP policy..."); set_crypto_policy_cipher_auth (stream->rtcp_cipher, stream->rtcp_auth, &policy.rtcp); if (stream->key) { gst_buffer_map (stream->key, &map, GST_MAP_READ); policy.key = (guchar *) map.data; } else { policy.key = tmp; } policy.ssrc.value = ssrc; policy.ssrc.type = ssrc_specific; policy.window_size = filter->replay_window_size; policy.next = NULL; /* If it is the first stream, create the session * If not, add the stream policy to the session */ if (filter->first_session) ret = srtp_create (&filter->session, &policy); else ret = srtp_add_stream (filter->session, &policy); if (stream->key) gst_buffer_unmap (stream->key, &map); if (ret == err_status_ok) { srtp_stream_t srtp_stream; srtp_stream = srtp_get_stream (filter->session, htonl (ssrc)); if (srtp_stream) { /* Here, we just set the ROC, but we also need to set the initial * RTP sequence number later, otherwise libsrtp will not be able * to get the right packet index. */ rdbx_set_roc (&srtp_stream->rtp_rdbx, stream->roc); filter->roc_changed = TRUE; } filter->first_session = FALSE; g_hash_table_insert (filter->streams, GUINT_TO_POINTER (stream->ssrc), stream); } return ret; }
int evrb_crypto_keys_compute(void* local_ctx, void* distant_ctx, int caller) { srtp_policy_t* loc_policy; srtp_policy_t* dist_policy; EVRB_CRYPTO* loc = (EVRB_CRYPTO*)local_ctx; EVRB_CRYPTO* dist = (EVRB_CRYPTO*)distant_ctx; unsigned char *master_key; int master_key_len; if(!local_ctx || !distant_ctx) return -1; loc_policy = (srtp_policy_t*)malloc(sizeof(srtp_policy_t)); dist_policy = (srtp_policy_t*)malloc(sizeof(srtp_policy_t)); if(!loc_policy || !dist_policy) return -1; memcpy(loc_policy, &default_policy, sizeof(srtp_policy_t)); memcpy(dist_policy, &default_policy, sizeof(srtp_policy_t)); loc_policy->ssrc.type = ssrc_any_outbound; dist_policy->ssrc.type = ssrc_any_inbound; if (loc->dh == NULL) return -1; master_key = dh_compute_key(loc->dh, dist->key, &master_key_len); #ifndef NDEBUG { int i; printf("key1=%s\nkey2=%s\n", loc->key, dist->key); printf("master_key(%d)=", master_key_len); for (i = 0; i < master_key_len; i++) printf("%02x", master_key[i]); printf("\n"); } #endif loc_policy->key = (uint8_t*)malloc(EVRB_KEY_SIZE); dist_policy->key = (uint8_t*)malloc(EVRB_KEY_SIZE); // TODO: better key derivation /* Simmetric keys */ if (caller) { memcpy(loc_policy->key, master_key, EVRB_KEY_SIZE); memcpy(dist_policy->key, master_key+EVRB_KEY_SIZE, EVRB_KEY_SIZE); } else { memcpy(loc_policy->key, master_key+EVRB_KEY_SIZE, EVRB_KEY_SIZE); memcpy(dist_policy->key, master_key, EVRB_KEY_SIZE); } if(srtp_create(&loc->srtp_session, loc_policy)) return -1; if(srtp_create(&dist->srtp_session, dist_policy)) return -1; return 0; }
/** * Probes and initializes. */ static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; int tp; /* transport protocol */ if (!strcmp (demux->psz_access, "dccp")) tp = IPPROTO_DCCP; else if (!strcmp (demux->psz_access, "rtptcp")) tp = IPPROTO_TCP; else if (!strcmp (demux->psz_access, "rtp")) tp = IPPROTO_UDP; else if (!strcmp (demux->psz_access, "udplite")) tp = IPPROTO_UDPLITE; else return VLC_EGENERIC; char *tmp = strdup (demux->psz_location); if (tmp == NULL) return VLC_ENOMEM; char *shost; char *dhost = strchr (tmp, '@'); if (dhost != NULL) { *(dhost++) = '\0'; shost = tmp; } else { dhost = tmp; shost = NULL; } /* Parses the port numbers */ int sport = 0, dport = 0; if (shost != NULL) sport = extract_port (&shost); if (dhost != NULL) dport = extract_port (&dhost); if (dport == 0) dport = 5004; /* avt-profile-1 port */ int rtcp_dport = var_CreateGetInteger (obj, "rtcp-port"); /* Try to connect */ int fd = -1, rtcp_fd = -1; switch (tp) { case IPPROTO_UDP: case IPPROTO_UDPLITE: fd = net_OpenDgram (obj, dhost, dport, shost, sport, tp); if (fd == -1) break; if (rtcp_dport > 0) /* XXX: source port is unknown */ rtcp_fd = net_OpenDgram (obj, dhost, rtcp_dport, shost, 0, tp); break; case IPPROTO_DCCP: #ifndef SOCK_DCCP /* provisional API (FIXME) */ # ifdef __linux__ # define SOCK_DCCP 6 # endif #endif #ifdef SOCK_DCCP var_Create (obj, "dccp-service", VLC_VAR_STRING); var_SetString (obj, "dccp-service", "RTPV"); /* FIXME: RTPA? */ fd = net_Connect (obj, dhost, dport, SOCK_DCCP, tp); #else msg_Err (obj, "DCCP support not included"); #endif break; case IPPROTO_TCP: fd = net_Connect (obj, dhost, dport, SOCK_STREAM, tp); break; } free (tmp); if (fd == -1) return VLC_EGENERIC; net_SetCSCov (fd, -1, 12); /* Initializes demux */ demux_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) { net_Close (fd); if (rtcp_fd != -1) net_Close (rtcp_fd); return VLC_EGENERIC; } p_sys->chained_demux = NULL; #ifdef HAVE_SRTP p_sys->srtp = NULL; #endif p_sys->fd = fd; p_sys->rtcp_fd = rtcp_fd; p_sys->max_src = var_CreateGetInteger (obj, "rtp-max-src"); p_sys->timeout = var_CreateGetInteger (obj, "rtp-timeout") * CLOCK_FREQ; p_sys->max_dropout = var_CreateGetInteger (obj, "rtp-max-dropout"); p_sys->max_misorder = var_CreateGetInteger (obj, "rtp-max-misorder"); p_sys->thread_ready = false; p_sys->autodetect = true; demux->pf_demux = NULL; demux->pf_control = Control; demux->p_sys = p_sys; p_sys->session = rtp_session_create (demux); if (p_sys->session == NULL) goto error; #ifdef HAVE_SRTP char *key = var_CreateGetNonEmptyString (demux, "srtp-key"); if (key) { vlc_gcrypt_init (); p_sys->srtp = srtp_create (SRTP_ENCR_AES_CM, SRTP_AUTH_HMAC_SHA1, 10, SRTP_PRF_AES_CM, SRTP_RCC_MODE1); if (p_sys->srtp == NULL) { free (key); goto error; } char *salt = var_CreateGetNonEmptyString (demux, "srtp-salt"); int val = srtp_setkeystring (p_sys->srtp, key, salt ? salt : ""); free (salt); free (key); if (val) { msg_Err (obj, "bad SRTP key/salt combination (%s)", vlc_strerror_c(val)); goto error; } } #endif if (vlc_clone (&p_sys->thread, (tp != IPPROTO_TCP) ? rtp_dgram_thread : rtp_stream_thread, demux, VLC_THREAD_PRIORITY_INPUT)) goto error; p_sys->thread_ready = true; return VLC_SUCCESS; error: Close (obj); return VLC_EGENERIC; }
/* * Initialize and start SRTP session with the given parameters. */ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start( pjmedia_transport *tp, const pjmedia_srtp_crypto *tx, const pjmedia_srtp_crypto *rx) { transport_srtp *srtp = (transport_srtp*) tp; srtp_policy_t tx_; srtp_policy_t rx_; err_status_t err; int cr_tx_idx = 0; int au_tx_idx = 0; int cr_rx_idx = 0; int au_rx_idx = 0; pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(tp && tx && rx, PJ_EINVAL); pj_lock_acquire(srtp->mutex); if (srtp->session_inited) { pjmedia_transport_srtp_stop(tp); } /* Get encryption and authentication method */ cr_tx_idx = au_tx_idx = get_crypto_idx(&tx->name); if (tx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_tx_idx = 0; if (tx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_tx_idx = 0; cr_rx_idx = au_rx_idx = get_crypto_idx(&rx->name); if (rx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_rx_idx = 0; if (rx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_rx_idx = 0; /* Check whether the crypto-suite requested is supported */ if (cr_tx_idx == -1 || cr_rx_idx == -1 || au_tx_idx == -1 || au_rx_idx == -1) { status = PJMEDIA_SRTP_ENOTSUPCRYPTO; goto on_return; } /* If all options points to 'NULL' method, just bypass SRTP */ if (cr_tx_idx == 0 && cr_rx_idx == 0 && au_tx_idx == 0 && au_rx_idx == 0) { srtp->bypass_srtp = PJ_TRUE; goto on_return; } /* Check key length */ if (tx->key.slen != (pj_ssize_t)crypto_suites[cr_tx_idx].cipher_key_len || rx->key.slen != (pj_ssize_t)crypto_suites[cr_rx_idx].cipher_key_len) { status = PJMEDIA_SRTP_EINKEYLEN; goto on_return; } /* Init transmit direction */ pj_bzero(&tx_, sizeof(srtp_policy_t)); pj_memmove(srtp->tx_key, tx->key.ptr, tx->key.slen); if (cr_tx_idx && au_tx_idx) tx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_tx_idx) tx_.rtp.sec_serv = sec_serv_conf; else if (au_tx_idx) tx_.rtp.sec_serv = sec_serv_auth; else tx_.rtp.sec_serv = sec_serv_none; tx_.key = (uint8_t*)srtp->tx_key; tx_.ssrc.type = ssrc_any_outbound; tx_.ssrc.value = 0; tx_.rtp.cipher_type = crypto_suites[cr_tx_idx].cipher_type; tx_.rtp.cipher_key_len = crypto_suites[cr_tx_idx].cipher_key_len; tx_.rtp.auth_type = crypto_suites[au_tx_idx].auth_type; tx_.rtp.auth_key_len = crypto_suites[au_tx_idx].auth_key_len; tx_.rtp.auth_tag_len = crypto_suites[au_tx_idx].srtp_auth_tag_len; tx_.rtcp = tx_.rtp; tx_.rtcp.auth_tag_len = crypto_suites[au_tx_idx].srtcp_auth_tag_len; tx_.next = NULL; err = srtp_create(&srtp->srtp_tx_ctx, &tx_); if (err != err_status_ok) { status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); goto on_return; } srtp->tx_policy = *tx; pj_strset(&srtp->tx_policy.key, srtp->tx_key, tx->key.slen); srtp->tx_policy.name=pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); /* Init receive direction */ pj_bzero(&rx_, sizeof(srtp_policy_t)); pj_memmove(srtp->rx_key, rx->key.ptr, rx->key.slen); if (cr_rx_idx && au_rx_idx) rx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_rx_idx) rx_.rtp.sec_serv = sec_serv_conf; else if (au_rx_idx) rx_.rtp.sec_serv = sec_serv_auth; else rx_.rtp.sec_serv = sec_serv_none; rx_.key = (uint8_t*)srtp->rx_key; rx_.ssrc.type = ssrc_any_inbound; rx_.ssrc.value = 0; rx_.rtp.sec_serv = crypto_suites[cr_rx_idx].service; rx_.rtp.cipher_type = crypto_suites[cr_rx_idx].cipher_type; rx_.rtp.cipher_key_len = crypto_suites[cr_rx_idx].cipher_key_len; rx_.rtp.auth_type = crypto_suites[au_rx_idx].auth_type; rx_.rtp.auth_key_len = crypto_suites[au_rx_idx].auth_key_len; rx_.rtp.auth_tag_len = crypto_suites[au_rx_idx].srtp_auth_tag_len; rx_.rtcp = rx_.rtp; rx_.rtcp.auth_tag_len = crypto_suites[au_rx_idx].srtcp_auth_tag_len; rx_.next = NULL; err = srtp_create(&srtp->srtp_rx_ctx, &rx_); if (err != err_status_ok) { srtp_dealloc(srtp->srtp_tx_ctx); status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); goto on_return; } srtp->rx_policy = *rx; pj_strset(&srtp->rx_policy.key, srtp->rx_key, rx->key.slen); srtp->rx_policy.name=pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); /* Declare SRTP session initialized */ srtp->session_inited = PJ_TRUE; /* Logging stuffs */ #if PJ_LOG_MAX_LEVEL >= 5 { char b64[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)]; int b64_len; /* TX crypto and key */ b64_len = sizeof(b64); status = pj_base64_encode((pj_uint8_t*)tx->key.ptr, tx->key.slen, b64, &b64_len); if (status != PJ_SUCCESS) b64_len = pj_ansi_sprintf(b64, "--key too long--"); else b64[b64_len] = '\0'; PJ_LOG(5, (srtp->pool->obj_name, "TX: %s key=%s", srtp->tx_policy.name.ptr, b64)); if (srtp->tx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name, "TX: disable%s%s", (cr_tx_idx?"":" enc"), (au_tx_idx?"":" auth"))); } /* RX crypto and key */ b64_len = sizeof(b64); status = pj_base64_encode((pj_uint8_t*)rx->key.ptr, rx->key.slen, b64, &b64_len); if (status != PJ_SUCCESS) b64_len = pj_ansi_sprintf(b64, "--key too long--"); else b64[b64_len] = '\0'; PJ_LOG(5, (srtp->pool->obj_name, "RX: %s key=%s", srtp->rx_policy.name.ptr, b64)); if (srtp->rx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name,"RX: disable%s%s", (cr_rx_idx?"":" enc"), (au_rx_idx?"":" auth"))); } } #endif on_return: pj_lock_release(srtp->mutex); return status; }
srtp_err_status_t test_dtls_srtp(void) { srtp_hdr_t *test_packet; int test_packet_len = 80; srtp_t s; srtp_policy_t policy; uint8_t key[SRTP_MAX_KEY_LEN]; uint8_t salt[SRTP_MAX_KEY_LEN]; unsigned int key_len, salt_len; srtp_profile_t profile; srtp_err_status_t err; /* create a 'null' SRTP session */ err = srtp_create(&s, NULL); if (err) return err; /* * verify that packet-processing functions behave properly - we * expect that these functions will return srtp_err_status_no_ctx */ test_packet = srtp_create_test_packet(80, 0xa5a5a5a5); if (test_packet == NULL) return srtp_err_status_alloc_fail; err = srtp_protect(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_protect() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_unprotect(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_unprotect() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_protect_rtcp(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_protect_rtcp() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_unprotect_rtcp(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_unprotect_rtcp() (got code %d)\n", err); return srtp_err_status_fail; } /* * set keys to known values for testing */ profile = srtp_profile_aes128_cm_sha1_80; key_len = srtp_profile_get_master_key_length(profile); salt_len = srtp_profile_get_master_salt_length(profile); memset(key, 0xff, key_len); memset(salt, 0xee, salt_len); srtp_append_salt_to_key(key, key_len, salt, salt_len); policy.key = key; /* initialize SRTP policy from profile */ err = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile); if (err) return err; err = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile); if (err) return err; policy.ssrc.type = ssrc_any_inbound; policy.ekt = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.next = NULL; err = srtp_add_stream(s, &policy); if (err) return err; err = srtp_dealloc(s); if (err) return err; free(test_packet); return srtp_err_status_ok; }
int rtp_receiver_init_srtp(rtp_receiver_t sender, const srtp_policy_t *policy) { return srtp_create(&sender->srtp_ctx, policy); }
err_status_t ortp_srtp_create(srtp_t *session, const srtp_policy_t *policy) { int i; i = srtp_create(session, policy); return i; }
srtp_err_status_t rtp_decoder_init_srtp(rtp_decoder_t decoder, unsigned int ssrc) { decoder->policy.ssrc.value = htonl(ssrc); return srtp_create(&decoder->srtp_ctx, &decoder->policy); }
/* * Initialize and start SRTP session with the given parameters. */ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start( pjmedia_transport *tp, const pjmedia_srtp_crypto *tx, const pjmedia_srtp_crypto *rx) { transport_srtp *srtp = (transport_srtp*) tp; srtp_policy_t tx_; srtp_policy_t rx_; err_status_t err; int cr_tx_idx = 0; int au_tx_idx = 0; int cr_rx_idx = 0; int au_rx_idx = 0; int crypto_suites_cnt; PJ_ASSERT_RETURN(tp && tx && rx, PJ_EINVAL); if (srtp->session_inited) { pjmedia_transport_srtp_stop(tp); } crypto_suites_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]); /* Get encryption and authentication method */ cr_tx_idx = au_tx_idx = get_crypto_idx(&tx->name); if (tx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_tx_idx = 0; if (tx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_tx_idx = 0; cr_rx_idx = au_rx_idx = get_crypto_idx(&rx->name); if (rx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_rx_idx = 0; if (rx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_rx_idx = 0; /* Check whether the crypto-suite requested is supported */ if (cr_tx_idx == -1 || cr_rx_idx == -1 || au_tx_idx == -1 || au_rx_idx == -1) return PJMEDIA_SRTP_ENOTSUPCRYPTO; /* If all options points to 'NULL' method, just bypass SRTP */ if (cr_tx_idx == 0 && cr_rx_idx == 0 && au_tx_idx == 0 && au_rx_idx == 0) { srtp->bypass_srtp = PJ_TRUE; return PJ_SUCCESS; } /* Check key length */ if (tx->key.slen != (pj_ssize_t)crypto_suites[cr_tx_idx].cipher_key_len || rx->key.slen != (pj_ssize_t)crypto_suites[cr_rx_idx].cipher_key_len) return PJMEDIA_SRTP_EINKEYLEN; /* Init transmit direction */ pj_bzero(&tx_, sizeof(srtp_policy_t)); pj_memmove(srtp->tx_key, tx->key.ptr, tx->key.slen); if (cr_tx_idx && au_tx_idx) tx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_tx_idx) tx_.rtp.sec_serv = sec_serv_conf; else if (au_tx_idx) tx_.rtp.sec_serv = sec_serv_auth; else tx_.rtp.sec_serv = sec_serv_none; tx_.key = (uint8_t*)srtp->tx_key; tx_.ssrc.type = ssrc_any_outbound; tx_.ssrc.value = 0; tx_.rtp.cipher_type = crypto_suites[cr_tx_idx].cipher_type; tx_.rtp.cipher_key_len = crypto_suites[cr_tx_idx].cipher_key_len; tx_.rtp.auth_type = crypto_suites[au_tx_idx].auth_type; tx_.rtp.auth_key_len = crypto_suites[au_tx_idx].auth_key_len; tx_.rtp.auth_tag_len = crypto_suites[au_tx_idx].srtp_auth_tag_len; tx_.rtcp = tx_.rtp; tx_.rtcp.auth_tag_len = crypto_suites[au_tx_idx].srtcp_auth_tag_len; tx_.next = NULL; err = srtp_create(&srtp->srtp_tx_ctx, &tx_); if (err != err_status_ok) { return PJMEDIA_ERRNO_FROM_LIBSRTP(err); } srtp->tx_policy = *tx; pj_strset(&srtp->tx_policy.key, srtp->tx_key, tx->key.slen); srtp->tx_policy.name=pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); /* Init receive direction */ pj_bzero(&rx_, sizeof(srtp_policy_t)); pj_memmove(srtp->rx_key, rx->key.ptr, rx->key.slen); if (cr_rx_idx && au_rx_idx) rx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_rx_idx) rx_.rtp.sec_serv = sec_serv_conf; else if (au_rx_idx) rx_.rtp.sec_serv = sec_serv_auth; else rx_.rtp.sec_serv = sec_serv_none; rx_.key = (uint8_t*)srtp->rx_key; rx_.ssrc.type = ssrc_any_inbound; rx_.ssrc.value = 0; rx_.rtp.sec_serv = crypto_suites[cr_rx_idx].service; rx_.rtp.cipher_type = crypto_suites[cr_rx_idx].cipher_type; rx_.rtp.cipher_key_len = crypto_suites[cr_rx_idx].cipher_key_len; rx_.rtp.auth_type = crypto_suites[au_rx_idx].auth_type; rx_.rtp.auth_key_len = crypto_suites[au_rx_idx].auth_key_len; rx_.rtp.auth_tag_len = crypto_suites[au_rx_idx].srtp_auth_tag_len; rx_.rtcp = rx_.rtp; rx_.rtcp.auth_tag_len = crypto_suites[au_rx_idx].srtcp_auth_tag_len; rx_.next = NULL; err = srtp_create(&srtp->srtp_rx_ctx, &rx_); if (err != err_status_ok) { srtp_dealloc(srtp->srtp_tx_ctx); return PJMEDIA_ERRNO_FROM_LIBSRTP(err); } srtp->rx_policy = *rx; pj_strset(&srtp->rx_policy.key, srtp->rx_key, rx->key.slen); srtp->rx_policy.name=pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); /* Declare SRTP session initialized */ srtp->session_inited = PJ_TRUE; PJ_LOG(5, (srtp->pool->obj_name, "TX: %s key=%s", srtp->tx_policy.name.ptr, octet_string_hex_string(tx->key.ptr, tx->key.slen))); if (srtp->tx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name,"TX: disable%s%s", (cr_tx_idx?"":" enc"), (au_tx_idx?"":" auth"))); } PJ_LOG(5, (srtp->pool->obj_name, "RX: %s key=%s", srtp->rx_policy.name.ptr, octet_string_hex_string(rx->key.ptr, rx->key.slen))); if (srtp->rx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name,"RX: disable%s%s", (cr_rx_idx?"":" enc"), (au_rx_idx?"":" auth"))); } return PJ_SUCCESS; }
void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len) { if(dtls == NULL) { JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n"); return; } janus_ice_component *component = (janus_ice_component *)dtls->component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return; } if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) { JANUS_LOG(LOG_ERR, "Alert already received, clearing up...\n"); return; } if(!dtls->ssl || !dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); return; } /* We just got a message, can we get rid of the last sent message? */ if(dtls->dtls_last_msg != NULL) { g_free(dtls->dtls_last_msg); dtls->dtls_last_msg = NULL; dtls->dtls_last_len = 0; } janus_dtls_fd_bridge(dtls); int written = BIO_write(dtls->read_bio, buf, len); JANUS_LOG(LOG_HUGE, " Written %d of those bytes on the read BIO...\n", written); janus_dtls_fd_bridge(dtls); int read = SSL_read(dtls->ssl, buf, len); JANUS_LOG(LOG_HUGE, " ...and read %d of them from SSL...\n", read); janus_dtls_fd_bridge(dtls); if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) { /* DTLS alert received, we should end it here */ JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id); return; } if(SSL_is_init_finished(dtls->ssl)) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS established, yay!\n", handle->handle_id); /* Check the remote fingerprint */ X509 *rcert = SSL_get_peer_certificate(dtls->ssl); if(!rcert) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote certificate??\n", handle->handle_id); } else { unsigned int rsize; unsigned char rfingerprint[EVP_MAX_MD_SIZE]; char remote_fingerprint[160]; char *rfp = (char *)&remote_fingerprint; if(handle->remote_hashing && !strcasecmp(handle->remote_hashing, "sha-1")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id); X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize); } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-256 fingerprint of remote certificate...\n", handle->handle_id); X509_digest(rcert, EVP_sha256(), (unsigned char *)rfingerprint, &rsize); } X509_free(rcert); rcert = NULL; int i = 0; for(i = 0; i < rsize; i++) { sprintf(rfp, "%.2X:", rfingerprint[i]); rfp += 3; } *(rfp-1) = 0; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n", handle->handle_id, handle->remote_hashing ? handle->remote_hashing : "sha-256", remote_fingerprint); if(!strcasecmp(remote_fingerprint, handle->remote_fingerprint ? handle->remote_fingerprint : "(none)")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Fingerprint is a match!\n", handle->handle_id); dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED; } else { /* FIXME NOT a match! MITM? */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Fingerprint is NOT a match! expected %s\n", handle->handle_id, handle->remote_fingerprint); dtls->dtls_state = JANUS_DTLS_STATE_FAILED; goto done; } if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) { /* Complete with SRTP setup */ unsigned char material[SRTP_MASTER_LENGTH*2]; unsigned char *local_key, *local_salt, *remote_key, *remote_salt; /* Export keying material for SRTP */ if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LENGTH*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { /* Oops... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); goto done; } /* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */ if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) { local_key = material; remote_key = local_key + SRTP_MASTER_KEY_LENGTH; local_salt = remote_key + SRTP_MASTER_KEY_LENGTH; remote_salt = local_salt + SRTP_MASTER_SALT_LENGTH; } else { remote_key = material; local_key = remote_key + SRTP_MASTER_KEY_LENGTH; remote_salt = local_key + SRTP_MASTER_KEY_LENGTH; local_salt = remote_salt + SRTP_MASTER_SALT_LENGTH; } /* Build master keys and set SRTP policies */ /* Remote (inbound) */ crypto_policy_set_rtp_default(&(dtls->remote_policy.rtp)); crypto_policy_set_rtcp_default(&(dtls->remote_policy.rtcp)); dtls->remote_policy.ssrc.type = ssrc_any_inbound; dtls->remote_policy.key = calloc(SRTP_MASTER_LENGTH+8, sizeof(char)); if(dtls->remote_policy.key == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); goto done; } memcpy(dtls->remote_policy.key, remote_key, SRTP_MASTER_KEY_LENGTH); memcpy(dtls->remote_policy.key + SRTP_MASTER_KEY_LENGTH, remote_salt, SRTP_MASTER_SALT_LENGTH); dtls->remote_policy.window_size = 128; dtls->remote_policy.allow_repeat_tx = 0; dtls->remote_policy.next = NULL; /* Local (outbound) */ crypto_policy_set_rtp_default(&(dtls->local_policy.rtp)); crypto_policy_set_rtcp_default(&(dtls->local_policy.rtcp)); dtls->local_policy.ssrc.type = ssrc_any_outbound; dtls->local_policy.key = calloc(SRTP_MASTER_LENGTH+8, sizeof(char)); if(dtls->local_policy.key == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); goto done; } memcpy(dtls->local_policy.key, local_key, SRTP_MASTER_KEY_LENGTH); memcpy(dtls->local_policy.key + SRTP_MASTER_KEY_LENGTH, local_salt, SRTP_MASTER_SALT_LENGTH); dtls->local_policy.window_size = 128; dtls->local_policy.allow_repeat_tx = 0; dtls->local_policy.next = NULL; /* Create SRTP sessions */ err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy)); if(res != err_status_ok) { /* Something went wrong... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res)); goto done; } JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy)); if(res != err_status_ok) { /* Something went wrong... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res)); goto done; } dtls->srtp_valid = 1; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); } done: if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) { /* Handshake successfully completed */ janus_ice_dtls_handshake_done(handle, component); } else { /* Something went wrong in either DTLS or SRTP... tell the plugin about it */ janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0); } } } }