ssl服務端原始碼
阿新 • • 發佈:2021-10-29
目錄結構
- ssl_server.h # 標頭檔案
- ssl_server.c # 程式碼檔案
- Makefile # makefile
- ca # 證書目錄
- ca.crt # CA證書
- 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); } /* 關閉監聽的 socket */ 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); } /* 基於 ctx 產生一個新的 SSL */ client_pNode->ssl = SSL_new(glbCTX); /* 將連線使用者的 socket 加入到 SSL */ SSL_set_fd(client_pNode->ssl, client_pNode->sockfd); /* 建立 SSL 連線 */ 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 庫初始化 */ SSL_library_init(); /* 載入所有 SSL 演算法 */ OpenSSL_add_all_algorithms(); /* 載入所有 SSL 錯誤訊息 */ SSL_load_error_strings(); printf("\n"); /* 以 SSL V2 和 V3 標準相容方式產生一個 SSL_CTX ,即 SSL Content Text */ glbCTX = SSL_CTX_new(SSLv23_server_method()); /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 單獨表示 V2 或 V3標準 */ 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) { /* 釋放 CTX */ SSL_CTX_free(glbCTX); } return 0; } int init_server(Connect_pNode pNode) { struct sockaddr_in server_addr; /* 開啟一個 socket 監聽 */ 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//LINPqfHGgAlaz7We0zW9zCYEeZF50G6KWWYbjy5fkERSj/agzKfNeLR0Jgvn4
EmIPDlUTAW95A6JUEpuFU0Hkh4Ne7wAuy65KCeaWYX29gNLU/xM1/XIX/0Ntj/Bl
qkNDMwPL6JksKnkZUro=
-----END CERTIFICATE-----
server.key
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCdr9SfvCI88GqTNMfofOvhQp2h2v+Lk2fQPeyf6kc5/MUGrX9G
vWU8en4fY/9gWbQmyAbbpctEpA9WWqLCLM276+5qjkoXR//RD8n0syYm3xilXJlk
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-----