目录结构
- ssl_server.h
- ssl_server.c
- Makefile
- ca
- ca.crt
- server.crt
- server.key
ssl_server.h
#ifndef _SSL_SERVER_H
#define _SSL_SERVER_H
#include <stdio.h>
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define MAXBUF 1024
#if 1
#define PORT 9487
#else
#define PORT 6789
#endif
#define LISTEN_NUM 5
#define log(fmt,...) printf("%s:%d:"fmt"\n",__func__,__LINE__,##__VA_ARGS__)
#define BUFFER_SIZE 1024
typedef struct connect_node{
int sockfd;
SSL *ssl;
}Connect_Node_T, *Connect_pNode;
SSL_CTX *glbCTX = NULL;
int init_server(Connect_pNode pNode);
int connect_client(Connect_pNode server_pNode, Connect_pNode client_pNode);
int close_connect(Connect_pNode pNode);
int init_connect_node(Connect_pNode pNode);
int test_ssl_io(Connect_pNode pNode);
int init_ssl();
int cleanup_ssl();
int ShowCerts(SSL * ssl);
#endif
ssl_server.c
#include "ssl_server.h"
void test()
{
int ret;
Connect_Node_T server_node, client_node;
ret = init_ssl();
if(ret != 0)
{
perror("init ssl ");
return;
}
ret = init_connect_node(&server_node);
if(ret != 0)
{
perror("init server connect node ");
return;
}
ret = init_server(&server_node);
if(ret != 0)
{
perror("init server ");
return;
}
for(;;)
{
init_connect_node(&client_node);
ret = connect_client(&server_node, &client_node);
if(ret != 0)
{
perror("connect client ");
close_connect(&client_node);
continue;
}
ret = test_ssl_io(&client_node);
if(ret != 0)
{
perror("test ssl io ");
}
close_connect(&client_node);
}
close_connect(&server_node);
cleanup_ssl();
}
int main(int argc, char **argv)
{
test();
return 0;
}
int connect_client(Connect_pNode server_pNode, Connect_pNode client_pNode)
{
socklen_t len;
struct sockaddr_in client_addr;
len = sizeof(struct sockaddr);
if ((client_pNode->sockfd = accept(server_pNode->sockfd, (struct sockaddr *) &client_addr, &len)) == -1)
{
perror("accept");
return -1;
}
else
{
printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port), client_pNode->sockfd);
}
client_pNode->ssl = SSL_new(glbCTX);
SSL_set_fd(client_pNode->ssl, client_pNode->sockfd);
if (SSL_accept(client_pNode->ssl) == -1)
{
perror("accept");
close(client_pNode->sockfd);
return -1;
}
if(ShowCerts(client_pNode->ssl) != 0)
{
perror("check crt");
return -1;
}
return 0;
}
int close_connect(Connect_pNode pNode)
{
if(pNode->ssl != NULL)
{
SSL_shutdown(pNode->ssl);
SSL_free(pNode->ssl);
pNode->ssl = NULL;
}
if(pNode->sockfd != -1)
{
close(pNode->sockfd);
pNode->sockfd = -1;
}
return 0;
}
int init_connect_node(Connect_pNode pNode)
{
pNode->sockfd = -1;
pNode->ssl = NULL;
return 0;
}
int test_ssl_io(Connect_pNode pNode)
{
char buf[MAXBUF + 1];
socklen_t len;
bzero(buf, MAXBUF + 1);
strcpy(buf, "server->client");
len = SSL_write(pNode->ssl, buf, strlen(buf));
if (len <= 0)
{
printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno, strerror(errno));
return -1;
}
else
{
printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len);
}
bzero(buf, MAXBUF + 1);
len = SSL_read(pNode->ssl, buf, MAXBUF);
if (len > 0)
{
printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
}
else
{
printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
return -1;
}
return 0;
}
int init_ssl()
{
char CAPATH[BUFFER_SIZE];
char *CANAME = "ca.crt";
char *serverCrtName = "server.crt";
char *serverKeyName = "server.key";
char serverCrt[BUFFER_SIZE], serverKey[BUFFER_SIZE], CAFILE[BUFFER_SIZE];
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
printf("\n");
glbCTX = SSL_CTX_new(SSLv23_server_method());
if (glbCTX == NULL)
{
perror("SSL new ctx ");
return -1;
}
else
{
printf("create ctx successful\n");
}
memset(CAPATH, 0, sizeof(CAPATH));
if(getcwd(CAPATH, sizeof(CAPATH)) == NULL)
{
perror("getcwd");
return -1;
}
strcat(CAPATH, "/ca/");
memset(CAFILE, 0, sizeof(CAFILE));
sprintf(CAFILE, "%s%s", CAPATH, CANAME);
if (SSL_CTX_load_verify_locations(glbCTX, CAFILE, NULL)<=0)
{
perror("load ca ");
return -1;
}
else
{
printf("load root crt success\n");
}
memset(serverCrt, 0, sizeof(serverCrt));
sprintf(serverCrt, "%s%s", CAPATH, serverCrtName);
if (SSL_CTX_use_certificate_file(glbCTX, serverCrt, SSL_FILETYPE_PEM) <= 0)
{
perror("load user crt ");
return -1;
}
else
{
printf("load user crt successful\n");
}
memset(serverKey, 0, sizeof(serverKey));
sprintf(serverKey, "%s%s", CAPATH, serverKeyName);
if (SSL_CTX_use_PrivateKey_file(glbCTX, serverKey, SSL_FILETYPE_PEM) <= 0)
{
perror("load user key ");
return -1;
}
else
{
printf("load user key successful\n");
}
if (!SSL_CTX_check_private_key(glbCTX))
{
perror("check user key ");
return -1;
}
else
{
printf("checking user key successful\n");
}
SSL_CTX_set_verify(glbCTX, SSL_VERIFY_PEER, NULL);
return 0;
}
int cleanup_ssl()
{
if(glbCTX != NULL)
{
SSL_CTX_free(glbCTX);
}
return 0;
}
int init_server(Connect_pNode pNode)
{
struct sockaddr_in server_addr;
if ((pNode->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
return -1;
}
else
{
printf("server socket created successful\n");
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(pNode->sockfd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind");
return -1;
}
else
{
printf("bind socket successful\n");
}
if (listen(pNode->sockfd, 5) == -1)
{
perror("listen");
return -1;
}
else
{
printf("begin listen\n");
}
return 0;
}
int ShowCerts(SSL * ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
if(SSL_get_verify_result(ssl) == X509_V_OK)
{
printf("证书验证通过\n");
}
else
{
printf("证书验证失败\n");
return -1;
}
if (cert != NULL)
{
printf("数字证书信息:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("证书: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("颁发者: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("无证书信息!\n");
return -1;
}
return 0;
}
makefile
EXE = ssl_server
OBJ = ssl_server.o
CC = gcc
CURRDIR = $(shell pwd)
CFLAGS = -Wall -lssl -lcrypto
INCLUDE = -I$(CURRDIR)
all : $(EXE)
$(EXE):$(OBJ)
$(CC) $(CFLAGS) $(INCLUDE) -o $(EXE) $(OBJ)
clean:
-rm -rf $(EXE) $(OBJ)
ca.crt
-----BEGIN CERTIFICATE-----
MIICZjCCAc+gAwIBAgIUFSyoO8SzaUFgjnlOZVRak6T2oqUwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTEwMjgwMzM3MjBaFw0yMjEw
MjgwMzM3MjBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEB
BQADgY0AMIGJAoGBAMV/aMOCdB2xaWC5Cr26R8rLJsK+JdC2otzs/o3qyWXggRQ6
g8vBQPFZ+OGldJtueJgrDbzrPhsJKF8eGfseXFlPg73iHkRjJ8nPe5pa3SCuaznU
3WwwzifSm4goE+x7rJyT8eTlGTdB2ONXkOR3d8kgTvLFnWPxM/6M6XUfBHszAgMB
AAGjUzBRMB0GA1UdDgQWBBTiHglejO5eKy4HlhV8bY3n3Wg1LjAfBgNVHSMEGDAW
gBTiHglejO5eKy4HlhV8bY3n3Wg1LjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4GBAF7QCa9Gb5PTYHbLTAULr1lpuuSgY89iD4l1EiAiMYq6KvbI5xmz
OoQMfcb4b286PzME71NNwNqc7i/c4iy/qZ51yDfTA7coAU+zprbp6fHUgxghmNZB
iNmqkNF0v6FYFie+BTSAU4HZbPmi6dpdg3zTVQGnv3Sx5gxjgJj7MJrK
-----END CERTIFICATE-----
server.crt
-----BEGIN CERTIFICATE-----
MIIB6jCCAVMCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDAeFw0yMTEwMjgwMzM4NDhaFw0yMjEwMjgwMzM4NDhaMDYxCzAJBgNVBAYTAkNO
MQswCQYDVQQIDAJHRDELMAkGA1UEBwwCU1oxDTALBgNVBAoMBFNDVFkwgZ8wDQYJ
KoZIhvcNAQEBBQADgY0AMIGJAoGBAJ2v1J+8IjzwapM0x+h86+FCnaHa/4uTZ9A9
7J/qRzn8xQatf0a9ZTx6fh9j/2BZtCbIBtuly0SkD1ZaosIszbvr7mqOShdH/9EP
yfSzJibfGKVcmWRQF58VgliuB7LLu1m2r8M1eQ5dmRb2uh+YW4uLJAJ4415yHVQB
s9HWuW9VAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUhw2CH1/sFwgDQe4b3XKbdoC
K
EmIPDlUTAW95A6JUEpuFU0Hkh4Ne7wAuy65KCeaWYX29gNLU/xM1/XIX/0Ntj/Bl
qkNDMwPL6JksKnkZUro=
-----END CERTIFICATE-----
server.key
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCdr9SfvCI88GqTNMfofOvhQp2h2v+Lk2fQPeyf6kc5/MUGrX9G
vWU8en4fY/9gWbQmyAbbpctEpA9WWqLCLM276+5qjkoXR
UBefFYJYrgeyy7tZtq/DNXkOXZkW9rofmFuLiyQCeONech1UAbPR1rlvVQIDAQAB
AoGAbXd668j3G8bqtXaWsNbICYDtXUdiz8ps7yuN8RX6jE7lmFUpXjps5SdEFxac
Wo7reWCzIhhenDAoVZJmGtZvm0aYcngL53oyGKdgu1dJfNAAltRPkFhOuG6uyVsI
MlSBul6n+GtZVlIbKVY7xU9YGwESVNB7WkyefNpr0/or0qECQQDL9vzI87+zPgcP
eSDyAxRxzBEqj2ik89gxb9Cdkrp5OufN0ohL6GnxdY36lz3mNXzVRf0KKzZsNLbI
zg/uc5O3AkEAxepp2g2lSZ5BmP+mYRfLkKaGe7zNH7BPNfV/JB6lbFzMqFg3Vma5
VcIO8QipuYuwIJzZ+iy6uhlbZ8EUS8HNUwJAbCSciv+SGLs+ixmyOh8f6+ZDA8nd
tfgEHNIoTiPJ8xUkaqDB211zLq8hhEhEbZbWhU4CiC25QU4BzB5VnBxzqQJAQUTu
RbAMW3vqbDebOhfr1Tdl0HbSOuodJVFh7ZqBuXvdLoNxNHhKFMMbxFe0CXHM0uSH
al7H8cmdAFmHhPhT6wJBAMvmlOzQOTX77jcShyqjcjjITfQK16Hgkt5weOT21Eq+
WMZD/3v9WbLIqrhtYfrjujGWJt30Lx+USuLRyco0YcA=
-----END RSA PRIVATE KEY-----
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了