const char* DtlsSocketContext::DefaultSrtpProfile = "SRTP_AES128_CM_SHA1_80";
X509 *DtlsSocketContext::mCert = nullptr;
EVP_PKEY *DtlsSocketContext::privkey = nullptr;
// 创建ssl 上下文,并设置证书和秘钥
// memory is only valid for duration of callback; must be copied if queueing
// is required
DtlsSocketContext::DtlsSocketContext() {
started = false;
ELOG_DEBUG("Creating Dtls factory, Openssl v %s", OPENSSL_VERSION_TEXT);
mContext = SSL_CTX_new(DTLS_method());
assert(mContext);
int r = SSL_CTX_use_certificate(mContext, mCert);
assert(r == 1);
r = SSL_CTX_use_PrivateKey(mContext, privkey);
assert(r == 1);
SSL_CTX_set_cipher_list(mContext, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSL_CTX_set_info_callback(mContext, SSLInfoCallback);
SSL_CTX_set_verify(mContext, SSL_VERIFY_PEER |SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
SSLVerifyCallback);
SSL_CTX_set_options(mContext, SSL_OP_NO_QUERY_MTU);
// SSL_CTX_set_session_cache_mode(mContext, SSL_SESS_CACHE_OFF);
// SSL_CTX_set_options(mContext, SSL_OP_NO_TICKET);
// Set SRTP profiles
r = SSL_CTX_set_tlsext_use_srtp(mContext, DefaultSrtpProfile);
assert(r == 0);
SSL_CTX_set_verify_depth(mContext, 2);
SSL_CTX_set_read_ahead(mContext, 1);
ELOG_DEBUG("DtlsSocketContext created");
}
// 关闭mSocket,释放mContext
DtlsSocketContext::~DtlsSocketContext() {
mSocket->close();
delete mSocket;
mSocket = nullptr;
SSL_CTX_free(mContext);
}
// 关闭mSocket
void DtlsSocketContext::close() {
mSocket->close();
}
// 当证书为空时,初始化openssl,但这个函数在程序没有被使用
void DtlsSocketContext::Init() {
ssl_thread_setup();
if (DtlsSocketContext::mCert == nullptr) {
OpenSSL_add_all_algorithms();
SSL_library_init();
SSL_load_error_strings();
ERR_load_crypto_strings();
createCert("sip:[email protected]", 365, 1024, DtlsSocketContext::mCert, DtlsSocketContext::privkey);
}
}
// 清理ssl线程
void DtlsSocketContext::Destroy() {
ssl_thread_cleanup();
}
// 创建客户端的DtlsSocket
DtlsSocket* DtlsSocketContext::createClient() {
return new DtlsSocket(this, DtlsSocket::Client);
}
// 创建服务器的DtlsSocket
DtlsSocket* DtlsSocketContext::createServer() {
return new DtlsSocket(this, DtlsSocket::Server);
}
void DtlsSocketContext::getMyCertFingerprint(char *fingerprint) {
DtlsSocket::computeFingerprint(DtlsSocketContext::mCert, fingerprint);
}
void DtlsSocketContext::setSrtpProfiles(const char *str) {
int r = SSL_CTX_set_tlsext_use_srtp(mContext, str);
assert(r == 0);
}
void DtlsSocketContext::setCipherSuites(const char *str) {
int r = SSL_CTX_set_cipher_list(mContext, str);
assert(r == 1);
}
// 获取ssl上下文
SSL_CTX* DtlsSocketContext::getSSLContext() {
return mContext;
}
// 解析包,并判断包的类型
DtlsSocketContext::PacketType DtlsSocketContext::demuxPacket(const unsigned char *data, unsigned int len) {
assert(len >= 1);
if ((data[0] == 0) || (data[0] == 1))
return stun;
if ((data[0] >= 128) && (data[0] <= 191))
return rtp;
if ((data[0] >= 20) && (data[0] <= 64))
return dtls;
return unknown;
}
// 获取本地证书指纹
std::string DtlsSocketContext::getFingerprint() const {
char fprint[100] = {};
mSocket->getMyCertFingerprint(fprint);
return std::string(fprint);
}
// 开始握手过程
void DtlsSocketContext::start() {
started = true;
mSocket->startClient();
}
// 处理接收的包数据
void DtlsSocketContext::read(const unsigned char* data, unsigned int len) {
mSocket->handlePacketMaybe(data, len);
}
// 设置接收对象
void DtlsSocketContext::setDtlsReceiver(DtlsReceiver *recv) {
receiver = recv;
}
// 将包发送到网络上
void DtlsSocketContext::write(const unsigned char* data, unsigned int len) {
if (receiver != NULL) {
receiver->onDtlsPacket(this, data, len);
}
}
// 超时处理
void DtlsSocketContext::handleTimeout() {
mSocket->handleTimeout();
}
// Dtls ssl握手完成,拿到srtp加解密所需的clientKey和serverKey秘钥
void DtlsSocketContext::handshakeCompleted() {
char fprint[100];
SRTP_PROTECTION_PROFILE *srtp_profile;
if (mSocket->getRemoteFingerprint(fprint)) {
ELOG_TRACE("Remote fingerprint == %s", fprint);
bool check = mSocket->checkFingerprint(fprint, strlen(fprint));
ELOG_DEBUG("Fingerprint check == %d", check);
SrtpSessionKeys* keys = mSocket->getSrtpSessionKeys();
unsigned char* cKey = (unsigned char*)malloc(keys->clientMasterKeyLen + keys->clientMasterSaltLen);
unsigned char* sKey = (unsigned char*)malloc(keys->serverMasterKeyLen + keys->serverMasterSaltLen);
memcpy(cKey, keys->clientMasterKey, keys->clientMasterKeyLen);
memcpy(cKey + keys->clientMasterKeyLen, keys->clientMasterSalt, keys->clientMasterSaltLen);
memcpy(sKey, keys->serverMasterKey, keys->serverMasterKeyLen);
memcpy(sKey + keys->serverMasterKeyLen, keys->serverMasterSalt, keys->serverMasterSaltLen);
// g_base64_encode must be free'd with g_free. Also, std::string's assignment operator does *not* take
// ownership of the passed in ptr; under the hood it copies up to the first null character.
gchar* temp = g_base64_encode((const guchar*)cKey, keys->clientMasterKeyLen + keys->clientMasterSaltLen);
std::string clientKey = temp;
g_free(temp); temp = NULL;
temp = g_base64_encode((const guchar*)sKey, keys->serverMasterKeyLen + keys->serverMasterSaltLen);
std::string serverKey = temp;
g_free(temp); temp = NULL;
ELOG_DEBUG("ClientKey: %s", clientKey.c_str());
ELOG_DEBUG("ServerKey: %s", serverKey.c_str());
free(cKey);
free(sKey);
delete keys;
srtp_profile = mSocket->getSrtpProfile();
if (srtp_profile) {
ELOG_DEBUG("SRTP Extension negotiated profile=%s", srtp_profile->name);
}
if (receiver != NULL) {
receiver->onHandshakeCompleted(this, clientKey, serverKey, srtp_profile->name);
}
} else {
ELOG_DEBUG("Peer did not authenticate");
}
}
//Dtls ssl对象握手失败
void DtlsSocketContext::handshakeFailed(const char *err) {
ELOG_WARN("DTLS Handshake Failure %s", err);
receiver->onHandshakeFailed(this, std::string(err));
}