1. 程式人生 > 其它 >ssl服務端原始碼

ssl服務端原始碼

目錄結構

- 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-----