Openssl Server C Demo

证书生成

rootPath=$(cd "$(dirname "$0")"; pwd)
#删除打包数据目录
OUTPUT=${rootPath}/build
rm -drf ${OUTPUT}
mkdir ${OUTPUT} 

# 生成CA证书
echo "-----------------------------生成CA证书----------------------------------"
name="standard_ca"
openssl genrsa -out ${OUTPUT}/${name}.key 2048  
openssl req -new -key ${OUTPUT}/${name}.key -out ${OUTPUT}/${name}.req -subj /C=CN/ST=JS/L=NJ/O=NJ/CN="127.0.0.1"
openssl x509 -req -days 3650 -in ${OUTPUT}/${name}.req -extfile ./openssl.cnf -extensions v3_ca -signkey ${OUTPUT}/${name}.key -out ${OUTPUT}/${name}.cer
openssl x509 -in ${OUTPUT}/${name}.cer -text -noout  
rm -f ${OUTPUT}/${name}.req

echo "-----------------------------Server签名证书----------------------------------"
# Server签名证书
name="standard_server_sign"
openssl genrsa -out ${OUTPUT}/${name}.key 2048  
openssl req -new -key ${OUTPUT}/${name}.key -out ${OUTPUT}/${name}.req -subj /C=CN/ST=JS/L=NJ/O=NJ/CN="127.0.0.1"
openssl x509 -req -days 3650 -in ${OUTPUT}/${name}.req -extfile ./openssl.cnf -extensions v3_req -CA ${OUTPUT}/standard_ca.cer -CAkey ${OUTPUT}/standard_ca.key -set_serial 1000000001 -extfile ${rootPath}/openssl.cnf -out ${OUTPUT}/${name}.cer  
openssl x509 -in ${OUTPUT}/${name}.cer -text -noout  
rm -f ${OUTPUT}/${name}.req


echo "-----------------------------客户端证书----------------------------------"
# 客户端证书
name="standard_client"
openssl genrsa -out ${OUTPUT}/${name}.key 2048  
openssl req -new -key ${OUTPUT}/${name}.key -out ${OUTPUT}/${name}.req -subj /C=CN/ST=JS/L=NJ/O=NJ/CN="127.0.0.1"
openssl x509 -req -days 3650 -in ${OUTPUT}/${name}.req -extfile ./openssl.cnf -extensions v3_req -CA ${OUTPUT}/standard_ca.cer -CAkey ${OUTPUT}/standard_ca.key -set_serial 1000000001 -extfile ${rootPath}/openssl.cnf -out ${OUTPUT}/${name}.cer  
openssl x509 -in ${OUTPUT}/${name}.cer -text -noout  
rm -f ${OUTPUT}/${name}.req

服务端代码

// HttpSvrDemo.cpp : 定义控制台应用程序的入口点。
//


#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"Ws2_32.lib")
#pragma comment(lib,"User32.lib")
#pragma comment(lib,"Advapi32.lib")
#pragma comment(lib,"Gdi32.lib")
#include <openssl\\ssl.h>
//#pragma comment(lib,"libeay32.lib")
//#pragma comment(lib,"ssleay32.lib")

#pragma warning(disable: 4996)

#define CERTF   "C:\\Users\\wjr\\Downloads\\standard_server_sign.cer"
#define KEYF    "C:\\Users\\wjr\\Downloads\\standard_server_sign.key"
#define CA		"C:\\Users\\wjr\\Downloads\\standard_ca.cer"



// 这是一个 https 服务端 Demo
int main()
{	
	WSADATA wsaData;
	sockaddr_in service = { 0 };
	SOCKET ListenSocket = INVALID_SOCKET;
	SOCKET AcceptSocket = INVALID_SOCKET;

	// 1.初始化 WSA 相关函数
	int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (err != 0)
	{
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\n", err);
		return -1;
	}

	// 2.初始化静态库 加载错误字符 加载算法库
	SSL_library_init();
	SSL_load_error_strings();
	SSLeay_add_ssl_algorithms();

	// 3.绑定本地端口并监听 ---- 摘自 MSDN
	ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ListenSocket == INVALID_SOCKET)
	{
		wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
			
	}
	//----------------------
	// The sockaddr_in structure specifies the address family,
	// IP address, and port for the socket that is being bound.
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = inet_addr("127.0.0.1");
	service.sin_port = htons(28801);

	int iResult = bind(ListenSocket, (SOCKADDR*)&service, sizeof(service));
	if (iResult == SOCKET_ERROR)
	{
		wprintf(L"bind function failed with error %d\n", WSAGetLastError());			
	}
	if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR)
	{
		wprintf(L"listen function failed with error: %d\n", WSAGetLastError());			
	}
	wprintf(L"Listening on socket...\n");

	// 4.等待建立连接
	while (TRUE)
	{		
		AcceptSocket = accept(ListenSocket, NULL, NULL);
		if (AcceptSocket == INVALID_SOCKET)
		{
			wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
			closesocket(ListenSocket);
			WSACleanup();
			return -1;
		}
		else
		{
			wprintf(L"Client connected.\n");
		}

		// 4.1将套接字与证书绑定

		const SSL_METHOD* meth = SSLv23_server_method();
		SSL_CTX* ctx = SSL_CTX_new(meth);

		 要求校验对方证书
		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

		加载CA
		if (SSL_CTX_load_verify_locations(ctx, CA, NULL) <= 0)
		{
			wprintf(L"SSL_CTX_use_certificate_file failed.\n");
			closesocket(AcceptSocket);
			continue;
		}

		if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
		{
			wprintf(L"SSL_CTX_use_certificate_file failed.\n");
			closesocket(AcceptSocket);
			continue;
		}

		if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
		{
			wprintf(L"SSL_CTX_use_PrivateKey_file failed.\n");
			closesocket(AcceptSocket);
			continue;
		}
		if (SSL_CTX_check_private_key(ctx) <= 0) 
		{
			wprintf(L"Private key does not match the certificate public key\n");
			closesocket(AcceptSocket);
			continue;
		}
		SSL* ssl = SSL_new(ctx);
		SSL_set_fd(ssl, AcceptSocket);
		if (SSL_accept(ssl) == -1)
		{
			int n = SSL_get_error(ssl, -1);					
			const char* p1 = SSL_state_string_long(ssl);
			printf("错误代码:%s\r\n", SSL_state_string_long(ssl));
			closesocket(AcceptSocket);
			continue;
		}

		// 4.2从SSL套接字读取数据
		char  buf[4096] = { 0 };
		int sslRead = SSL_read(ssl, buf, 4095);		
		printf("%s\n", buf);

		// 4.3往SSL套接字写入数据
		char szTemp[400] = "HTTP/1.1 200 OK\r\nServer: bfe/1.0.8.14\r\nDate: Mon, 29 Feb 2016 06:21:46 GMT\r\nContent-Type: text/html\r\nContent-Length: 70\r\nConnection: keep-alive\r\n\r\n<html>\r\n<head><title>200 Ok</title></head><body> 200 OK </body></html>";
		int nCount = strlen(szTemp);
		int nRet = 0;
		do
		{
			nRet += SSL_write(ssl, szTemp, nCount);
			if (nRet >= nCount)
			{
				break;
			}
		} while (true);		
		closesocket(AcceptSocket);
		AcceptSocket = INVALID_SOCKET;
	}
	closesocket(ListenSocket);
	return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值