C 将简单套接字转换为SSL套接字

C 将简单套接字转换为SSL套接字,c,linux,sockets,unix,ssl,C,Linux,Sockets,Unix,Ssl,我编写了简单的C程序,它们使用套接字(“客户机”和“服务器”)。 (UNIX/Linux使用) 服务器端只创建一个套接字: sockfd = socket(AF_INET, SOCK_STREAM, 0); 然后将其绑定到sockaddr: bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 倾听(并接受和阅读): 客户端创建套接字,然后向其写入 现在,我想以最简单、最田园诗般、最整洁、最快捷的方式将这个简

我编写了简单的C程序,它们使用套接字(“客户机”和“服务器”)。 (UNIX/Linux使用)

服务器端只创建一个套接字:

sockfd = socket(AF_INET, SOCK_STREAM, 0);
然后将其绑定到sockaddr:

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
倾听(并接受和阅读):

客户端创建套接字,然后向其写入

现在,我想以最简单、最田园诗般、最整洁、最快捷的方式将这个简单的连接转换为SSL连接


我已经尝试添加到我的项目中,但是我找不到一种简单的方法来实现我想要的东西。

OpenSSL非常困难。如果谈判做得不对,很容易意外地丢掉你所有的安全感。(见鬼,我个人被一个bug咬了一口,curl没有完全正确地读取OpenSSL警报,并且无法与某些站点通信。)


如果你真的想快速而简单,在你的程序前放一个一天的电话。在不同的进程中使用SSL不会减慢您的速度:

使用OpenSSL时有几个步骤。您必须创建一个SSL证书,该证书可以包含具有私钥的证书。请确保指定证书的确切位置(此示例在根目录中)。有很多很好的教程

其中包括:

#include <openssl/applink.c>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
现在我们来看看大部分功能。您可能需要在连接上添加while循环

int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}
更新 应使用最适合您需要的TLS方法调用
SSL\u CTX\u new
,以支持较新版本的安全性,而不是
SSLv23\u server\u方法()
。见:

TLS_方法(),TLS_服务器_方法(),TLS_客户端_方法()。 这些是通用版本的灵活SSL/TLS方法。实际使用的协议版本将协商为客户端和服务器共同支持的最高版本。支持的协议有SSLv3、TLSv1、TLSv1.1、TLSv1.2和TLSv1.3

对于像我这样的人:

<>在目录>代码> DEMOS/SSL/中有一个例子,C++中有示例代码。现在只能通过历史记录获取:

您可能需要找到一个工作版本,我最初在2015年11月6日发布了这个答案。我不得不编辑源代码——不多


证书:
demos/certs/apps/
中的pem:

这里是我的示例ssl套接字服务器线程(多连接)

#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(int argc,char*argv[])
{
BreakerMindsLServer吊杆;
boom.Start(123、“/home/user/c++/qt/BreakermindServer/certificate.crt”、“/home/user/c++/qt/BreakermindServer/private.key”);
返回0;
}

如果您正在寻找“安全连接”,而不是特别是SSL,您可以查看驻留在应用程序外部的东西,并将其设置为通过SSH连接发送流量。就应用程序SSL而言,如果您了解SSL/TLS的工作原理,那么OpenSSL非常容易。如果您想要一个替代方案,请尝试yaSSL或gnuTLS。OpenSSl是C程序员的标准。如果你在这方面有困难,你应该问一下。检查一下这个。第二部分对我来说太高级、太难了。但是第2部分值得一看。也可以检查一下。但是我刚刚听到了关于Openssl有多糟糕的观点,以及其他值得一试的替代方案。另一种选择是使用外部SSL包装工具,如
stunnel
,stunnel4包在基于Debian的发行版中,使用起来很简单。与在服务器中添加适当的SSL支持相比,有一些局限性,但这对于快速解决方案来说是好的。我喜欢stunnel,因为它似乎适合UNIX软件工具方法。这是一个实用的答案,但它并没有真正回答这个问题。stunnel于2016年被放弃。自述文件建议:不要像我想的那么“简单”,但最后(感谢上帝!)我看到了一些代码。这是跨平台的还是仅适用于unix/unix类系统?我在多个平台上使用过类似的代码:arm、linux和windows。不过最后一个
if
是错误的。如果没有调用
ssl\u err,DH密码将无法工作
ssl\u CTX\u set\u tmp\u DH[\u callback]()
。刚刚发现没有它,所有密码都无法工作的困难,产生了40号警报。@DevNull
SSLv23\u server\u方法()
声明服务器理解SSLv2和v3,现在已弃用。若要支持TLS 1.1和1.2,请将该方法替换为
TLS\u server\u method()
。请将解决方案直接包含在您的SO帖子中。
void InitializeSSL()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void DestroySSL()
{
    ERR_free_strings();
    EVP_cleanup();
}

void ShutdownSSL()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}
int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}
SSL_read(cSSL, (char *)charBuffer, nBytesToRead);
SSL_write(cSSL, "Hi :3\n", 6);
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <iostream>

#include <breakermindsslserver.h>

using namespace std;

int main(int argc, char *argv[])
{
    BreakermindSslServer boom;
    boom.Start(123,"/home/user/c++/qt/BreakermindServer/certificate.crt", "/home/user/c++/qt/BreakermindServer/private.key");
    return 0;
}