ssl客戶端原始碼
阿新 • • 發佈:2021-10-29
目錄結構
- ssl_client.h # 標頭檔案
- ssl_client.c # 程式碼檔案
- Makefile # makefile
- ca # 證書目錄
- ca.crt # CA證書
- client.crt # 服務端證書
- client.key # 服務端金鑰
ssl_client.h
#ifndef _SSL_CLIENT_H #define _SSL_CLIENT_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 0 #define PORT 6789 #define IPADDR "127.0.0.1" #else #define PORT 9487 #define IPADDR "10.0.0.51" #endif #define log(fmt,...) printf("%s:%d:"fmt"\n",__func__,__LINE__,##__VA_ARGS__) #define BUFFER_SIZE 1024 #define HTTP_GET_KEEPALIVE "GET %s HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n" typedef struct connect_node{ int sockfd; SSL *ssl; }Connect_Node_T, *Connect_pNode; SSL_CTX *glbCTX = NULL; int connect_socket(Connect_pNode pNode); int connect_ssl(Connect_pNode 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_client.c
#include "ssl_client.h" void test() { int ret = 0; Connect_Node_T client_node; ret = init_ssl(); if(ret != 0) { printf("init ssl error\n"); return; } ret = init_connect_node(&client_node); if(ret != 0) { printf("init connect node error\n"); return; } ret = connect_socket(&client_node); if(ret != 0) { printf("connect socket error\n"); return; } ret = connect_ssl(&client_node); if(ret != 0) { printf("connect ssl error\n"); return; } ret = test_ssl_io(&client_node); if(ret != 0) { printf("test ssl io error\n"); return; } close_connect(&client_node); cleanup_ssl(); } int main(int argc, char **argv) { test(); return 0; } int connect_socket(Connect_pNode pNode) { struct sockaddr_in server_addr; /* 建立一個 socket 用於 tcp 通訊 */ if ((pNode->sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket"); return -1; } printf("socket created\n"); /* 初始化伺服器端(對方)的地址和埠資訊 */ bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); if(inet_pton(AF_INET, IPADDR, &server_addr.sin_addr) <= 0) { perror("inet_pton : "); return -1; } printf("address created\n"); /* 連線伺服器 */ if (connect(pNode->sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { perror("Connect "); return -1; } printf("server connected at fd :%d\n", pNode->sockfd); 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 init_ssl() { char CAPATH[BUFFER_SIZE]; char *CANAME = "ca.crt"; char *clientCrtName = "client.crt"; char *clientKeyName = "client.key"; char clientCrt[BUFFER_SIZE], clientKey[BUFFER_SIZE], CAFILE[BUFFER_SIZE]; SSL_library_init(); SSL_load_error_strings(); glbCTX = SSL_CTX_new(SSLv23_client_method()); if (glbCTX == NULL) { perror("SSL new ctx "); return -1; } 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); printf("%s\n", CAFILE); if (SSL_CTX_load_verify_locations(glbCTX, CAFILE, NULL)<=0) { perror("load ca "); return -1; } else { printf("load root crt success\n"); } /* 載入使用者的數字證書, 此證書用來發送給服務端。 證書裡包含有公鑰 */ memset(clientCrt, 0, sizeof(clientCrt)); sprintf(clientCrt, "%s%s", CAPATH, clientCrtName); if (SSL_CTX_use_certificate_file(glbCTX, clientCrt, SSL_FILETYPE_PEM) <= 0) { perror("load crt "); return -1; } else { printf("load user crt successful\n"); } /* 載入使用者私鑰 */ memset(clientKey, 0, sizeof(clientKey)); sprintf(clientKey, "%s%s", CAPATH, clientKeyName); if (SSL_CTX_use_PrivateKey_file(glbCTX, clientKey, 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 test_ssl_io(Connect_pNode pNode) { int len; char buffer[MAXBUF + 1]; bzero(buffer, MAXBUF + 1); strcpy(buffer, "from client->server"); /* 發訊息給伺服器 */ len = SSL_write(pNode->ssl, buffer, strlen(buffer)); if (len < 0) { printf("訊息'%s'傳送失敗!錯誤程式碼是%d,錯誤資訊是'%s'\n",buffer, errno, strerror(errno)); } else { printf("訊息'%s'傳送成功,共傳送了%d個位元組!\n",buffer, len); } /* 接收對方發過來的訊息,最多接收 MAXBUF 個位元組 */ bzero(buffer, MAXBUF + 1); /* 接收伺服器來的訊息 */ len = SSL_read(pNode->ssl, buffer, MAXBUF); if (len > 0) { printf("接收訊息成功:'%s',共%d個位元組的資料\n", buffer, len); } else { printf("訊息接收失敗!錯誤程式碼是%d,錯誤資訊是'%s'\n",errno, strerror(errno)); return -1; } 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; } int connect_ssl(Connect_pNode pNode) { /* 基於 ctx 產生一個新的 SSL */ pNode->ssl = SSL_new(glbCTX); if(pNode->ssl == NULL) { perror("new ssl "); return -1; } if(SSL_set_fd(pNode->ssl, pNode->sockfd) != 1) { perror("ssl set fd "); return -1; } /* 建立 SSL 連線 */ if (SSL_connect(pNode->ssl) == -1) { perror("ssl connect "); return -1; } else { printf("Connected with %s encryption\n", SSL_get_cipher(pNode->ssl)); } if(ShowCerts(pNode->ssl) != 0) { return -1; } return 0; }
makefile
EXE = ssl_client
OBJ = ssl_client.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-----
client.crt
-----BEGIN CERTIFICATE-----
MIIB8TCCAVoCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDAeFw0yMTEwMjkwMzAxMjVaFw0yMjEwMjkwMzAxMjVaMD0xCzAJBgNVBAYTAkNO
MQswCQYDVQQIDAJHRDEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDuhC7M0TCJftIVK43iUFGdsgQe
tTJjQmGcVD1/f25UPgyf2HGSMSKiy+/KdAxeAGmuDQcmbYomnOYMIycZZOo8/P+a
YetBvzdw1wTVha+Pmak7eJglKXguYng6YGLj4oHhxG3kaGd9JWejouLVR5dKTDqq
cdMUawLAzuRFD/fKkQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAKUaJDr5hkzF5isg
9/CG130K3ROQcif7+fvLu/2v36ujdbfh6hqvN2FvfofRFyK1m3rFYLTT7h2vfift
6mGg+2l+s2z1S2tYVnHNggR3WG191rXEr9nf+0wBj04S+et1YTfll2DuD2wi3YVA
G/W4AMpItfg1eGpaCeZVE4M0EE9R
-----END CERTIFICATE-----
client.key
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDuhC7M0TCJftIVK43iUFGdsgQetTJjQmGcVD1/f25UPgyf2HGS
MSKiy+/KdAxeAGmuDQcmbYomnOYMIycZZOo8/P+aYetBvzdw1wTVha+Pmak7eJgl
KXguYng6YGLj4oHhxG3kaGd9JWejouLVR5dKTDqqcdMUawLAzuRFD/fKkQIDAQAB
AoGBAIbYDglXPsSNAUJctEM9O1cW/ENMF2eMcNjLu1Toezx/M+3ulQ6cXsOA3lkr
0I4YV6bB0MgF57O6wkgcW498wPuQdI31IRKNdZcvTElOy4O+Xwv6DPJwJee8mSe+
fd+oHkVXDyvKJyHqXnzuD4Nzw3ptnmMQWDYgJoIfCzrFXYr9AkEA+jkpu9Bi7dxe
C4sfV8Y9b9rdYVKk4AYje2dngj4d6rndsTtiUZpob3Ocy29d4KJU2SK71slAzkB/
X2e8zc5pywJBAPQF1LS7YLl9XgEd4a/vArS/pCbImoAfwmffFKJBcj8u+f+yCTFx
uzeAaOVdDkKPBCi1TXk1RQcOM6lH94QtwZMCQCGYUSkdNlsXLi1AlYm0XQVKjlSF
wwss59Cmtnf/HQcpw0ELZwzrvT/Rdui9YA5L3TZ1+mBBDwliEXfetrOvFfcCQQDx
e7+2JuQeS9E2O7L23wkHg8rXUpeKiWNiVWHe+/MqUbu27SGp24nQ7/NeX4tYFJ2i
B2EmvK+VvtkjAYQROxKfAkEAlOZlJFAIRkjpROy1tfZ87aTXbShrctq4Ayt31cvE
Um5/lY1B8ZIduZM3P3X6G2cVZSPEDJ0P9R6LZkoL3kHMpg==
-----END RSA PRIVATE KEY-----