90行代码实现C语言版https服务器,基于openssl

为了实现C语言版的https服务器(ubuntu linux),我查了很多资料,最后发现是非常简单好写的,在此向大家做个分享。

首先大致了解一下https的工作原理,下面这张图解释得非常好。

而openssl又对上面这张图里的一些功能进行了合并封装,让我们用起来更加方便简洁。

首先我们需要安装openssl开发包:

apt install openssl libssl-dev

运行前需要准备好证书fullchain.pem和私钥privkey.pem兩個文件,可用certbot免費生成ssl證書,方法如下文所述:

Ubuntu Linux 24.04 使用certbot生成ssl证书_ubuntu certbot-优快云博客

然后就可以编译和運行下面的mini版https server了 (https.c)

/*
gcc https.c -lssl -lcrypto   -o https
*/

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define BufSize 30 * 1024

int create_socket_listen(int port)
{
  int s;
  struct sockaddr_in addr;

  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = htonl(INADDR_ANY);

  s = socket(AF_INET, SOCK_STREAM, 0);  if (s < 0) {   perror("Unable to create socket");  exit(EXIT_FAILURE);  }
  if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {  perror("Unable to bind");  exit(EXIT_FAILURE); }
  if (listen(s, 1) < 0) { perror("Unable to listen"); exit(EXIT_FAILURE);   }

  return s;
}


SSL_CTX* initSSL(const char* cert, const char* key)
{
  //todo 可能存在泄露
  SSL_CTX* ctx;


  /* SSL 库初始化 */
  SSL_library_init();
  /* 载入所有 SSL 算法 */
  OpenSSL_add_all_algorithms();
  /* 载入所有 SSL 错误消息 */
  SSL_load_error_strings();
  /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text, 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
  ctx = SSL_CTX_new(SSLv23_server_method()); if (ctx == NULL) { ERR_print_errors_fp(stdout);  return NULL; }
  

  /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
  if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0) {  ERR_print_errors_fp(stdout);  return NULL;  }
  /* 载入用户私钥 */
  if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {   ERR_print_errors_fp(stdout);   return NULL;  }
  /* 检查用户私钥是否正确 */
  if (!SSL_CTX_check_private_key(ctx)) {  ERR_print_errors_fp(stdout);  return NULL; }


  return ctx;
}


int main(int argc, char** argv)
{
  int port = 5555;
  int sock;
  SSL_CTX* ctx;
  char buf[BufSize];

  /* Ignore broken pipe signals */
  signal(SIGPIPE, SIG_IGN);

  ctx = initSSL("./fullchain.pem", "./privkey.pem"); if (ctx == NULL) { return 0; }

  sock = create_socket_listen(port);

  /* Handle connections */
  while (1) 
  {
    struct sockaddr_in addr;
    unsigned int len = sizeof(addr);
    SSL* ssl;
    const char reply[] = "HTTP/1.1 200 OK\r\nDate: Fri, 22 May 2009 06:07:21 GMT\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><head></head><body>hello world</body></html>";

    int client = accept(sock, (struct sockaddr*)&addr, &len);  if (client < 0) {  perror("Unable to accept"); exit(EXIT_FAILURE);  }

    ssl = SSL_new(ctx); SSL_set_fd(ssl, client);
    if (SSL_accept(ssl) <= 0) { ERR_print_errors_fp(stderr); goto end; }

    int size = SSL_read(ssl, buf, BufSize); printf("ssl_read(%d): \n%s\n", size, buf); 

    SSL_write(ssl, reply, strlen(reply));

  end:
    SSL_shutdown(ssl);  SSL_free(ssl);  close(client);
  }

  close(sock);
  SSL_CTX_free(ctx);
}

编译命令和運行:

gcc https.c -lssl -lcrypto   -o https
./https
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuzen

您的资助将帮助我创作更好的作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值