Licode-DtlsSocket源码分析
Posted tongwlipi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Licode-DtlsSocket源码分析相关的知识,希望对你有一定的参考价值。
// 通过mSocketContext拿到设置了证书和私钥的ssl Context,创建ssl对象,分配输入和输出Bio
DtlsSocket::DtlsSocket(DtlsSocketContext* socketContext, enum SocketType type):
mSocketContext(socketContext),
mSocketType(type),
mHandshakeCompleted(false) {
ELOG_DEBUG("Creating Dtls Socket");
mSocketContext->setDtlsSocket(this);
SSL_CTX* mContext = mSocketContext->getSSLContext();
assert(mContext);
mSsl = SSL_new(mContext);
assert(mSsl != 0);
SSL_set_mtu(mSsl, DTLS_MTU);
mSsl->ctx = mContext;
mSsl->session_ctx = mContext;
switch (type) {
case Client:
SSL_set_connect_state(mSsl);
// SSL_set_mode(mSsl, SSL_MODE_ENABLE_PARTIAL_WRITE |
// SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
break;
case Server:
SSL_set_accept_state(mSsl);
SSL_set_verify(mSsl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, dummy_cb);
break;
default:
assert(0);
}
BIO* memBIO1 = BIO_new(BIO_s_mem());
mInBio = BIO_new(BIO_f_dwrap());
BIO_push(mInBio, memBIO1);
BIO* memBIO2 = BIO_new(BIO_s_mem());
mOutBio = BIO_new(BIO_f_dwrap());
BIO_push(mOutBio, memBIO2);
SSL_set_bio(mSsl, mInBio, mOutBio);
SSL_accept(mSsl);
ELOG_DEBUG("Dtls Socket created");
}
// 析构函数,关闭ssl对象
DtlsSocket::~DtlsSocket() {
close();
}
// 释放ssl对象
void DtlsSocket::close() {
// Properly shutdown the socket and free it - note: this also free's the BIO's
if (mSsl != NULL) {
ELOG_DEBUG("SSL Shutdown");
SSL_shutdown(mSsl);
SSL_free(mSsl);
mSsl = NULL;
}
}
// 开启ssl客户端握手操作
void DtlsSocket::startClient() {
assert(mSocketType == Client);
doHandshakeIteration();
}
// 处理包
bool DtlsSocket::handlePacketMaybe(const unsigned char* bytes, unsigned int len) {
if (mSsl == NULL) {
ELOG_WARN("handlePacketMaybe called after DtlsSocket closed: %p", this);
return false;
}
DtlsSocketContext::PacketType pType = DtlsSocketContext::demuxPacket(bytes, len);
if (pType != DtlsSocketContext::dtls) {
return false;
}
if (mSsl == nullptr) {
return false;
}
(void) BIO_reset(mInBio);
(void) BIO_reset(mOutBio);
int r = BIO_write(mInBio, bytes, len);
assert(r == static_cast<int>(len)); // Can't happen
// Note: we must catch any below exceptions--if there are any
try {
doHandshakeIteration();
} catch (int e) {
return false;
}
return true;
}
// 强制重传
void DtlsSocket::forceRetransmit() {
(void) BIO_reset(mInBio);
(void) BIO_reset(mOutBio);
BIO_ctrl(mInBio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, 0);
doHandshakeIteration();
}
// DTLS ssl握手操作,握手完成拿到协商后 srtp的秘钥
void DtlsSocket::doHandshakeIteration() {
boost::mutex::scoped_lock lock(handshakeMutex_);
char errbuf[1024];
int sslerr;
if (mHandshakeCompleted)
return;
int r = SSL_do_handshake(mSsl);
errbuf[0] = 0;
ERR_error_string_n(ERR_peek_error(), errbuf, sizeof(errbuf));
// See what was written
unsigned char *outBioData;
int outBioLen = BIO_get_mem_data(mOutBio, &outBioData);
if (outBioLen > DTLS_MTU) {
ELOG_WARN("message: BIO data bigger than MTU - packet could be lost, outBioLen %u, MTU %u",
outBioLen, DTLS_MTU);
}
// Now handle handshake errors */
switch (sslerr = SSL_get_error(mSsl, r)) {
case SSL_ERROR_NONE:
mHandshakeCompleted = true;
mSocketContext->handshakeCompleted();
break;
case SSL_ERROR_WANT_READ:
break;
default:
ELOG_ERROR("SSL error %d", sslerr);
mSocketContext->handshakeFailed(errbuf);
// Note: need to fall through to propagate alerts, if any
break;
}
// If mOutBio is now nonzero-length, then we need to write the
// data to the network. TODO(pedro): warning, MTU issues!
if (outBioLen) {
mSocketContext->write(outBioData, outBioLen);
}
}
// 拿到远端认证指纹
bool DtlsSocket::getRemoteFingerprint(char *fprint) {
X509* x = SSL_get_peer_certificate(mSsl);
if (!x) { // No certificate
return false;
}
computeFingerprint(x, fprint);
X509_free(x);
return true;
}
// 将传入指纹与远端指纹进行对比验证
bool DtlsSocket::checkFingerprint(const char* fingerprint, unsigned int len) {
char fprint[100];
if (getRemoteFingerprint(fprint) == false) {
return false;
}
// used to be strncasecmp
if (strncmp(fprint, fingerprint, len)) {
ELOG_WARN("Fingerprint mismatch, got %s expecting %s", fprint, fingerprint);
return false;
}
return true;
}
// 获取本地指纹信息
void DtlsSocket::getMyCertFingerprint(char *fingerprint) {
mSocketContext->getMyCertFingerprint(fingerprint);
}
// 获取srtp的秘钥信息
SrtpSessionKeys* DtlsSocket::getSrtpSessionKeys() {
// TODO(pedro): probably an exception candidate
assert(mHandshakeCompleted);
SrtpSessionKeys* keys = new SrtpSessionKeys();
unsigned char material[SRTP_MASTER_KEY_LEN << 1];
if (!SSL_export_keying_material(mSsl, material, sizeof(material), "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
return keys;
}
size_t offset = 0;
memcpy(keys->clientMasterKey, &material[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(keys->serverMasterKey, &material[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(keys->clientMasterSalt, &material[offset], SRTP_MASTER_KEY_SALT_LEN);
offset += SRTP_MASTER_KEY_SALT_LEN;
memcpy(keys->serverMasterSalt, &material[offset], SRTP_MASTER_KEY_SALT_LEN);
offset += SRTP_MASTER_KEY_SALT_LEN;
keys->clientMasterKeyLen = SRTP_MASTER_KEY_KEY_LEN;
keys->serverMasterKeyLen = SRTP_MASTER_KEY_KEY_LEN;
keys->clientMasterSaltLen = SRTP_MASTER_KEY_SALT_LEN;
keys->serverMasterSaltLen = SRTP_MASTER_KEY_SALT_LEN;
return keys;
}
// 获取srtp的profile
SRTP_PROTECTION_PROFILE* DtlsSocket::getSrtpProfile() {
// TODO(pedro): probably an exception candidate
assert(mHandshakeCompleted);
return SSL_get_selected_srtp_profile(mSsl);
}
// Fingerprint is assumed to be long enough
void DtlsSocket::computeFingerprint(X509 *cert, char *fingerprint) {
unsigned char md[EVP_MAX_MD_SIZE];
int r;
unsigned int i, n;
// r = X509_digest(cert, EVP_sha1(), md, &n);
r = X509_digest(cert, EVP_sha256(), md, &n);
// TODO(javier) - is sha1 vs sha256 supposed to come from DTLS handshake?
// fixing to to SHA-256 for compatibility with current web-rtc implementations
assert(r == 1);
for (i = 0; i < n; i++) {
sprintf(fingerprint, "%02X", md[i]); // NOLINT
fingerprint += 2;
if (i < (n-1))
*fingerprint++ = ':';
else
*fingerprint++ = 0;
}
}
void DtlsSocket::handleTimeout() {
(void) BIO_reset(mInBio);
(void) BIO_reset(mOutBio);
if (DTLSv1_handle_timeout(mSsl) > 0) {
ELOG_DEBUG("Dtls timeout occurred!");
// See what was written
unsigned char *outBioData;
int outBioLen = BIO_get_mem_data(mOutBio, &outBioData);
if (outBioLen > DTLS_MTU) {
ELOG_WARN("message: BIO data bigger than MTU - packet could be lost, outBioLen %u, MTU %u",
outBioLen, DTLS_MTU);
}
// If mOutBio is now nonzero-length, then we need to write the
// data to the network. TODO(pedro): warning, MTU issues!
if (outBioLen) {
mSocketContext->write(outBioData, outBioLen);
}
}
}
以上是关于Licode-DtlsSocket源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段
mysql jdbc源码分析片段 和 Tomcat's JDBC Pool
Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段
Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段