UnixStreamSocket::UnixStreamSocket(int fd) : ::UnixStreamSocket::UnixStreamSocket(fd, NS_MAX_SIZE) { MS_TRACE_STD(); // Create the JSON reader. { Json::CharReaderBuilder builder; Json::Value settings = Json::nullValue; Json::Value invalid_settings; builder.strictMode(&settings); MS_ASSERT(builder.validate(&invalid_settings), "invalid Json::CharReaderBuilder"); this->jsonReader = builder.newCharReader(); } // Create the JSON writer. { Json::StreamWriterBuilder builder; Json::Value invalid_settings; builder["commentStyle"] = "None"; builder["indentation"] = ""; builder["enableYAMLCompatibility"] = false; builder["dropNullPlaceholders"] = false; MS_ASSERT(builder.validate(&invalid_settings), "invalid Json::StreamWriterBuilder"); this->jsonWriter = builder.newStreamWriter(); } }
inline RTC::SrtpSession::Profile DtlsTransport::GetNegotiatedSrtpProfile() { MS_TRACE(); RTC::SrtpSession::Profile negotiated_srtp_profile = RTC::SrtpSession::Profile::NONE; // Ensure that the SRTP profile has been negotiated. SRTP_PROTECTION_PROFILE* ssl_srtp_profile = SSL_get_selected_srtp_profile(this->ssl); if (!ssl_srtp_profile) { return negotiated_srtp_profile; } // Get the negotiated SRTP profile. for (auto it = DtlsTransport::srtpProfiles.begin(); it != DtlsTransport::srtpProfiles.end(); ++it) { SrtpProfileMapEntry* profile_entry = &(*it); if (std::strcmp(ssl_srtp_profile->name, profile_entry->name) == 0) { MS_DEBUG("chosen SRTP profile: %s", profile_entry->name); negotiated_srtp_profile = profile_entry->profile; } } MS_ASSERT(negotiated_srtp_profile != RTC::SrtpSession::Profile::NONE, "chosen SRTP profile is not an available one"); return negotiated_srtp_profile; }
/* split encryptedPackage as [uint64_t:encData] */ inline uint64_t GetEncodedData(std::string& encData, const std::string& encryptedPackage) { if (encryptedPackage.size() < 8) { throw cybozu::Exception("ms:GetEncodedData:tool small") << encryptedPackage.size(); } const char *p = &encryptedPackage[0]; const uint64_t size = cybozu::Get64bitAsLE(p); dprintf("package size:header %d encryptedPackage %d\n", (int)size, (int)encryptedPackage.size()); MS_ASSERT(encryptedPackage.size() - 8 >= size); encData = encryptedPackage.substr(8); return size; }
void DtlsTransport::Run(Role localRole) { MS_TRACE(); MS_ASSERT(localRole == Role::CLIENT || localRole == Role::SERVER, "local DTLS role must be 'client' or 'server'"); Role previousLocalRole = this->localRole; if (localRole == previousLocalRole) { MS_ERROR("same local DTLS role provided, doing nothing"); return; } // If the previous local DTLS role was 'client' or 'server' do reset. if (previousLocalRole == Role::CLIENT || previousLocalRole == Role::SERVER) { MS_DEBUG("resetting DTLS due to local role change"); Reset(); } // Update local role. this->localRole = localRole; // Set state and notify the listener. this->state = DtlsState::CONNECTING; this->listener->onDtlsConnecting(this); switch (this->localRole) { case Role::CLIENT: MS_DEBUG("running [role:client]"); SSL_set_connect_state(this->ssl); SSL_do_handshake(this->ssl); SendPendingOutgoingDtlsData(); SetTimeout(); break; case Role::SERVER: MS_DEBUG("running [role:server]"); SSL_set_accept_state(this->ssl); SSL_do_handshake(this->ssl); break; default: MS_ABORT("invalid local DTLS role"); break; } }
inline void DtlsTransport::ProcessHandshake() { MS_TRACE(); MS_ASSERT(this->handshakeDone, "handshake not done yet"); // If the remote fingerprint is not yet set then do nothing (this method // will be called when the fingerprint is set). if (this->remoteFingerprint.algorithm == FingerprintAlgorithm::NONE) { MS_DEBUG("remote fingerprint not yet set, waiting for it"); return; } // Validate the remote fingerprint. if (!CheckRemoteFingerprint()) { Reset(); // Set state and notify the listener. this->state = DtlsState::FAILED; this->listener->onDtlsFailed(this); return; } // Get the negotiated SRTP profile. RTC::SrtpSession::Profile srtp_profile; srtp_profile = GetNegotiatedSrtpProfile(); if (srtp_profile != RTC::SrtpSession::Profile::NONE) { // Extract the SRTP keys (will notify the listener with them). ExtractSrtpKeys(srtp_profile); } else { // NOTE: We assume that "use_srtp" DTLS extension is required even if // there is no audio/video. MS_WARN("SRTP profile not negotiated"); Reset(); // Set state and notify the listener. this->state = DtlsState::FAILED; this->listener->onDtlsFailed(this); } }
inline void DtlsTransport::ExtractSrtpKeys(RTC::SrtpSession::Profile srtp_profile) { MS_TRACE(); uint8_t srtp_material[MS_SRTP_MASTER_LENGTH * 2]; uint8_t* srtp_local_key; uint8_t* srtp_local_salt; uint8_t* srtp_remote_key; uint8_t* srtp_remote_salt; uint8_t srtp_local_master_key[MS_SRTP_MASTER_LENGTH]; uint8_t srtp_remote_master_key[MS_SRTP_MASTER_LENGTH]; int ret; ret = SSL_export_keying_material(this->ssl, srtp_material, MS_SRTP_MASTER_LENGTH * 2, "EXTRACTOR-dtls_srtp", 19, nullptr, 0, 0); MS_ASSERT(ret != 0, "SSL_export_keying_material() failed"); switch (this->localRole) { case Role::SERVER: srtp_remote_key = srtp_material; srtp_local_key = srtp_remote_key + MS_SRTP_MASTER_KEY_LENGTH; srtp_remote_salt = srtp_local_key + MS_SRTP_MASTER_KEY_LENGTH; srtp_local_salt = srtp_remote_salt + MS_SRTP_MASTER_SALT_LENGTH; break; case Role::CLIENT: srtp_local_key = srtp_material; srtp_remote_key = srtp_local_key + MS_SRTP_MASTER_KEY_LENGTH; srtp_local_salt = srtp_remote_key + MS_SRTP_MASTER_KEY_LENGTH; srtp_remote_salt = srtp_local_salt + MS_SRTP_MASTER_SALT_LENGTH; break; default: MS_ABORT("no DTLS role set"); break; } // Create the SRTP local master key. std::memcpy(srtp_local_master_key, srtp_local_key, MS_SRTP_MASTER_KEY_LENGTH); std::memcpy(srtp_local_master_key + MS_SRTP_MASTER_KEY_LENGTH, srtp_local_salt, MS_SRTP_MASTER_SALT_LENGTH); // Create the SRTP remote master key. std::memcpy(srtp_remote_master_key, srtp_remote_key, MS_SRTP_MASTER_KEY_LENGTH); std::memcpy(srtp_remote_master_key + MS_SRTP_MASTER_KEY_LENGTH, srtp_remote_salt, MS_SRTP_MASTER_SALT_LENGTH); // Set state and notify the listener. this->state = DtlsState::CONNECTED; this->listener->onDtlsConnected(this, srtp_profile, srtp_local_master_key, MS_SRTP_MASTER_LENGTH, srtp_remote_master_key, MS_SRTP_MASTER_LENGTH); }
void DtlsTransport::SetRemoteFingerprint(Fingerprint fingerprint) { MS_TRACE(); MS_ASSERT(fingerprint.algorithm != FingerprintAlgorithm::NONE, "no fingerprint algorithm provided"); this->remoteFingerprint = fingerprint; // The remote fingerpring may have been set after DTLS handshake was done, // so we may need to process it now. if (this->handshakeDone && this->state != DtlsState::CONNECTED) { MS_DEBUG("handshake already done, processing it right now"); ProcessHandshake(); } }
/** * Reject the Request. * @param reason Description string. */ void Request::Reject(const char* reason) { MS_TRACE(); static const Json::StaticString k_id("id"); static const Json::StaticString k_rejected("rejected"); static const Json::StaticString k_reason("reason"); MS_ASSERT(!this->replied, "Request already replied"); this->replied = true; Json::Value json(Json::objectValue); json[k_id] = (Json::UInt)this->id; json[k_rejected] = true; if (reason) json[k_reason] = reason; this->channel->Send(json); }
void Request::Accept(Json::Value &data) { MS_TRACE(); static Json::Value empty_data(Json::objectValue); static const Json::StaticString k_id("id"); static const Json::StaticString k_accepted("accepted"); static const Json::StaticString k_data("data"); MS_ASSERT(!this->replied, "Request already replied"); this->replied = true; Json::Value json(Json::objectValue); json[k_id] = (Json::UInt)this->id; json[k_accepted] = true; if (data.isObject()) json[k_data] = data; else json[k_data] = empty_data; this->channel->Send(json); }
inline bool DtlsTransport::CheckRemoteFingerprint() { MS_TRACE(); MS_ASSERT(this->remoteFingerprint.algorithm != FingerprintAlgorithm::NONE, "remote fingerprint not set"); X509* certificate; uint8_t binary_fingerprint[EVP_MAX_MD_SIZE]; unsigned int size = 0; char hex_fingerprint[(EVP_MAX_MD_SIZE * 2) + 1]; const EVP_MD* hash_function; int ret; certificate = SSL_get_peer_certificate(this->ssl); if (!certificate) { MS_WARN("no certificate was provided by the peer"); return false; } switch (this->remoteFingerprint.algorithm) { case FingerprintAlgorithm::SHA1: hash_function = EVP_sha1(); break; case FingerprintAlgorithm::SHA224: hash_function = EVP_sha224(); break; case FingerprintAlgorithm::SHA256: hash_function = EVP_sha256(); break; case FingerprintAlgorithm::SHA384: hash_function = EVP_sha384(); break; case FingerprintAlgorithm::SHA512: hash_function = EVP_sha512(); break; default: MS_ABORT("unknown algorithm"); } ret = X509_digest(certificate, hash_function, binary_fingerprint, &size); X509_free(certificate); if (ret == 0) { MS_ERROR("X509_digest() failed"); return false; } // Convert to hexadecimal format in lowecase without colons. for (unsigned int i = 0; i < size; i++) { std::sprintf(hex_fingerprint + (i * 2), "%.2x", binary_fingerprint[i]); } hex_fingerprint[size * 2] = '\0'; if (this->remoteFingerprint.value.compare(hex_fingerprint) != 0) { MS_WARN("fingerprint in the remote certificate (%s) does not match the announced one (%s)", hex_fingerprint, this->remoteFingerprint.value.c_str()); return false; } MS_DEBUG("valid remote fingerprint"); return true; }