OpenSSL DTLS服务器实施C ++

问题描述

我正在尝试在C ++中实现DTLS服务器包装。
我打算做的是,当我收到一条消息时,如果客户端未知,则假设这是一次握手并尝试完成它。 如果知道客户端,则假定它是常规会话消息。

在这里遇到的问题是我的程序希望发送相同的消息两次以正确处理它(一次是“是否知道对等方?”部分,一次是SSL_accept / SSL_read部分)。

我认为我没有正确设置BIO,但是我不知道这样做的正确方法

这是我当前文件的外观:

/* server.hpp */

#ifndef _DTLS_SERVER_
#define _DTLS_SERVER_


#include <atomic>
#include <mutex>
#include <vector>

#include <arpa/inet.h>
#include <assert.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <map>
#include <algorithm>

class DTLSServer{

    private:




    public:

    static int generate_cookie(SSL *ssl,unsigned char *cookie,unsigned int *cookie_len); //placeholder

    static int verify_cookie(SSL *ssl,const unsigned char *cookie,unsigned int cookie_len); //placeholder
    struct client
    {
        BIO *bio;
        SSL *ssl;
        std::string onConnect(const uint16_t& p_sock,const std::string&,SSL_CTX *p_ctx);
        std::string onMessage(const std::string&);
    };

    // fd to use
    void init(const int &sock);


    DTLSServer();
    ~DTLSServer();

    //void stop(int p_signal);

    // if unkNown pair => adds new client => handshake else returns decyphered message
    std::string autoConnect(const sockaddr_in &p_addr,const std::string p_string);

    // remove client p_addr:p_port
    void removeClient(const std::string &p_addr,const uint16_t &p_port);

    // return added client p_addr:p_port
    client &createClient(const std::string &p_addr,const uint16_t &p_port);

    private:
    
    SSL_CTX *i_ctx;
    std::map<std::pair<std::string,uint16_t>,client>i_clients;
    uint64_t i_securitySessionsLifeTime;
    std::mutex i_dtlsMutex;
    int i_sock;

    public:

};

#endif
/* server.cpp */

#include "server.hpp"
#include <unistd.h>
#include <iostream>
#include <thread>

char cookie_str[] = "cookie";

DTLSServer::DTLSServer(){}

DTLSServer::~DTLSServer()
{
    i_dtlsMutex.lock();
    for(auto &l_cli : i_clients)
    {
        removeClient(l_cli.first.first,l_cli.first.second);
    }
    SSL_CTX_free(i_ctx);
    i_dtlsMutex.unlock();
}

std::string DTLSServer::autoConnect(const sockaddr_in &p_addr,const std::string p_string){

    char l_sTraddress[INET_ADDRSTRLEN];
    inet_ntop(AF_INET,&p_addr.sin_addr.s_addr,l_sTraddress,INET_ADDRSTRLEN);

    std::string l_addr(l_sTraddress);
    uint16_t l_port = ntohs(p_addr.sin_port);

    std::lock_guard<std::mutex>l_guard(i_dtlsMutex);

    auto l_cli = std::find_if(i_clients.begin(),i_clients.end(),// looking for {addr,port} in clients
        [l_addr,l_port](const std::pair<std::pair<std::string,client> &el) // {(addr,port),client}
        {
            return l_addr == el.first.first
            && l_port == el.first.second;
        });
    if(l_cli!=i_clients.end()) // found a client
    {
        std::cout << "received message from " << l_addr << ":" << l_port << std::endl;
        std::string retString = l_cli->second.onMessage(p_string); // decyphers message
        if(retString == "TO REMOVE")
            removeClient(l_addr,l_port);
        return retString;
    }
    else // new client
    {
        std::cout << "adding " << l_addr << ":" << l_port << std::endl;
        client &l_client = createClient(l_addr,l_port); // adding new client
        auto l_newcli = std::find_if(i_clients.begin(),[l_addr,client> &el)
        {
            return l_addr == el.first.first
            && l_port == el.first.second;
        });
        if(l_newcli==i_clients.end())
        {
            std::cout << "Couldn't find added client" << std::endl;
            return "";
        }
        else
            std::cout << "valid" << std::endl;
        return l_newcli->second.onConnect(i_sock,p_string,i_ctx); // creating SSL session for new client
    }
}

DTLSServer::client &DTLSServer::createClient(const std::string &p_addr,const uint16_t &p_port)
{
    std::pair<std::string,uint16_t> l_pair = {p_addr,p_port};
    i_clients.insert(std::pair<std::pair<std::string,client>(l_pair,client()));
    return i_clients.at(l_pair);
}

void DTLSServer::removeClient(const std::string &p_addr,const uint16_t &p_port)
{
    auto l_cli = std::find_if(i_clients.begin(),port} in clients
        [&p_addr,&p_port](const std::pair<std::pair<std::string,client}
        {
            return p_addr == el.first.first
            && p_port == el.first.second;
        });
    if(l_cli!=i_clients.end()){
        SSL_free(l_cli->second.ssl);
        l_cli->second.ssl = nullptr;
        i_clients.erase(l_cli);
    }
    else
    {
        std::cout << "Could not delete" << std::endl;
    }
}

void DTLSServer::init(const int &sock)
{
    i_sock = sock;
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_ciphers();
    memcpy(cookie_str,"cookie",7);

    i_ctx = SSL_CTX_new(DTLS_server_method());
    /*if(SSL_CTX_set_cipher_list(i_ctx,"AES256-SHA256")!=1) //CLIENT PART
    {
        std::cout << "Could not set cipher" << std::endl;
    }*/
    SSL_CTX_set_min_proto_version(i_ctx,DTLS1_2_VERSION);
    SSL_CTX_use_certificate_chain_file(i_ctx,"server-cert.pem");
    SSL_CTX_use_PrivateKey_file(i_ctx,"server-key.pem",SSL_FILETYPE_PEM);
    int l_ret = SSL_CTX_load_verify_locations(i_ctx,"root-ca.pem",NULL);
    fprintf(stderr,"SSL_CTX_load_verify_locations -> %d\n",l_ret);
    l_ret = SSL_CTX_set_default_verify_file(i_ctx);
    fprintf(stderr,"SSL_CTX_set_default_verify_file -> %d\n",l_ret);
    SSL_CTX_set_verify(i_ctx,SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,NULL);

    SSL_CTX_set_cookie_generate_cb(i_ctx,generate_cookie);
    SSL_CTX_set_cookie_verify_cb(i_ctx,verify_cookie);
}

std::string DTLSServer::client::onConnect(const uint16_t & p_sock,const std::string& p_msg,SSL_CTX *p_ctx)
{
    std::cout << "about to connect" << std::endl;
    ssl = SSL_new(p_ctx);
    if(nullptr==ssl)
        std::cout << "Couldn't create ssl session" << std::endl;
    bio = BIO_new_dgram(p_sock,BIO_NOCLOSE);
    if(nullptr==bio)
        std::cout << "Couldn't create ssl bio" << std::endl;
    SSL_set_bio(ssl,bio,bio);
    //write(p_sock,p_msg.c_str(),p_msg.size());
    //BIO_write(bio,p_msg.size());
    
    int needed = BIO_get_read_request(bio);
    std::cout << "about to accept"<< std::endl;
    int ret = SSL_accept(ssl);
    //int ret = 0;
    std::cout << "accepted"<< std::endl;
    if (ret < 0)
    {
        std::cout << "Failed to complete Handshake as " << strerror(errno) << std::endl;    
    }
    return "";
}

std::string DTLSServer::client::onMessage(const std::string& p_msg)
{

    int err = BIO_write(bio,&p_msg[0],p_msg.size());
    
    int needed = BIO_get_read_request(bio);
    
    char l_msg[1500] = {0};
    /*if(needed > 0) 
        std::cout << "critical error" << std::endl;*/
    int ret = SSL_read(ssl,&l_msg[0],1500);
    if(ret < 0)
    {
        std::cout << "unvalid message" << std::endl;
        return "TO REMOVE";
    }
    else if(0 == ret)
    {
        std::cout << "client to remove" << std::endl;
        return "TO REMOVE";
    }
    else
    {
        std::cout << "valid message" << std::endl;
        std::string l_m{l_msg};
        return "MESSAGE IS : " + l_m;
    }
    return "";

}


int DTLSServer::generate_cookie(SSL *ssl,unsigned int *cookie_len)
{
    memmove(cookie,cookie_str,sizeof(cookie_str)-1);
    *cookie_len = sizeof(cookie_str)-1;

    return 1;
}

int DTLSServer::verify_cookie(SSL *ssl,unsigned int cookie_len)
{
    return sizeof(cookie_str)-1==cookie_len && memcmp(cookie,sizeof(cookie_str)-1)==0;
}
/* main.cpp */

#include "server.hpp"
#include <iostream>

int main()
{
    DTLSServer l_dtls;
    int l_socket;
    if ((l_socket = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
        std::cout << "Could not create socket. " << strerror(errno) << std::endl;
        return 1;
    }

    struct sockaddr_in l_sendingAddress;
    l_sendingAddress.sin_family = AF_INET;
    inet_pton(AF_INET,"127.0.0.19",&l_sendingAddress.sin_addr.s_addr);
    l_sendingAddress.sin_port = htons(8888);

    //Binding socket
    if(bind(l_socket,reinterpret_cast<sockaddr *>(&l_sendingAddress),sizeof(l_sendingAddress)) < 0)
    {
        std::cout << "Could not bind. " << strerror(errno) << std::endl;
        return 1;
    }


    l_dtls.init(l_socket);
    char l_buffer[2000] = {0};
    sockaddr_in l_client;
    socklen_t l_clientLen = sizeof(l_client);
    while(1)
    {
        ssize_t l_bytesReceived = recvfrom(l_socket,&l_buffer,2000,MSG_DONTWAIT,reinterpret_cast<sockaddr *>(&l_client),&l_clientLen);
        if (l_bytesReceived == -1)
        {
            continue;
        }
        std::string l_string{l_buffer,static_cast<size_t>(l_bytesReceived)};
        std::cout << l_dtls.autoConnect(l_client,l_string) << std::endl;
        memset(l_buffer,2000);
    }
    return 0;
}

我的工作主要基于以下来源: https://github.com/stepheny/openssl-dtls-custom-bio

如何设置我的BIO去做我想要他们做的事情?
我必须创建自定义BIO吗?

提前感谢您的建议:)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)