windows openssl安装和基本使用(代码演示)

概述

本文主要讲到了openssl的基本使用方法,开发环境为windows,开发工具为VS2019.本文主要是说明openssl如何使用,不介绍任何理论知识,如果有不懂的,请自行百度。个人建议下一个everything查询工具,真的很好用,比window自带的查询快了很多,可以查询自己想要的文件

OPENSSL安装

安装过程网上有很多,OPENSSL安装,注意你安装的OPENSSL的版本以及位数(32位或者64位),假如我安装的是64位的openssl,安装目录为D:\Program Files\OpenSSL-Win64,你可以自行选择你的安装目录,安装完成后,查看安装的openssl版本,使用控制台输入openssl version即可
在这里插入图片描述

秘钥key和公钥的生成

在控制命令行中输入以下命令:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365

网上有很多生成秘钥和公钥的文章,不过都没成功,最后在stackoverflow找到了可以用的方法,原文地址为:openssl秘钥和公钥的生成,以下是截图
在这里插入图片描述
Enter PEM pass phrase:提示输入pem文件的密码,注意,后面要用到这个密码,可以使用自己常用的密码,输入后会再次确认密码,然后就是一些基本信息,可以默认为空。截图如下,基本上这时候就得到了秘钥key.pem和公钥cert.pem,后面要用到这2个文件。,生成的位置为当前目录,比如我的就是在C:\Users\86138,即控制台的显示目录
在这里插入图片描述

项目设置

使用VS创建一个控制台项目,创建一个客户端和服务器项目,由于我下载的是64位,openssl3.0版本。因此我项目也是64位的。
在这里插入图片描述
项目的配置,服务器端和客户端都是相同配置,这里我就只说一个即可,主要是设置openssl的lib和头文件的路径,这和使用任外部库都是一样的。截图如下,注意我的openssl安装位置为D:\Program Files\OpenSSL-Win64,请选择你安装位置即可。
在这里插入图片描述
预处理器里添加2个定义:CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;
在这里插入图片描述
附加依赖项:libssl.lib;openssl.lib;libcrypto.lib;liblegacy.lib;
在这里插入图片描述
最后将前面生成的cert.pem和key.pem放到exe目录下,为什么放到这个目录,是因为下面的代码用到的这2个文件是当前目录,不管怎么样,只要能找到这2个文件即可。
在这里插入图片描述
配置很简单,就上面几步,基本上就可以了。

代码部分

客户端代码

#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <string.h>
# include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define FAIL    -1
#pragma comment(lib, "Ws2_32.lib")
//Added the LoadCertificates how in the server-side makes.    
int OpenConnection(const char* hostname, int port)
{
	SOCKET sd;
	struct hostent* host;
	struct sockaddr_in addr;

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &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;
	}

	sd = socket(PF_INET, SOCK_STREAM, 0);
	/bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(hostname);
	int ret = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
	if ( ret != 0)
	{
		//close(sd);
		perror(hostname);
		abort();
	}
	return sd;
}

SSL_CTX* InitCTX(void)
{
	//SSL_METHOD* method;
	SSL_CTX* ctx;

	//OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
	SSL_load_error_strings();   /* Bring in and register error messages */
	SSL_METHOD const* meth = SSLv23_client_method();  /* Create new client-method instance */
	//method = TLSv1_method();
	ctx = SSL_CTX_new(meth);   /* Create new context */
	if (ctx == NULL)
	{
		ERR_print_errors_fp(stderr);
		printf("Eroor: %s\n", stderr);
		abort();
	}
	return ctx;
}

void ShowCerts(SSL* ssl)
{
	X509* cert;
	char* line1, * line2;

	cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
	if (cert != NULL)
	{
		printf("Server certificates:\n");
		line1 = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
		printf("Subject: %s\n", line1);
		//free(line);       /* free the malloc'ed string */
		line2 = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
		printf("Issuer: %s\n", line2);
		//free(line);       /* free the malloc'ed string */
		//X509_free(cert);     /* free the malloc'ed certificate copy */
	}
	else
		printf("No certificates.\n");
}

int main(int count, char* strings[])
{
	SSL_CTX* ctx;
	SOCKET server;
	SSL* ssl;
	char buf[1024];
	int bytes;
	char const *hostname, *portnum;

	SSL_library_init();
	hostname = "127.0.0.1";
	portnum = "1030";

	ctx = InitCTX();
	server = OpenConnection(hostname, atoi(portnum));
	ssl = SSL_new(ctx);      /* create new SSL connection state */
	//SSL_set_fd(ssl, server);    /* attach the socket descriptor */
	BIO* bio = BIO_new_socket(server, BIO_NOCLOSE);
	SSL_set_bio(ssl, bio, bio);
	SSL_set_connect_state(ssl);
	if (SSL_connect(ssl) == FAIL)   /* perform the connection */
	{
		printf("Eroor: %s\n", stderr);
		ERR_print_errors_fp(stderr);
	}
	else
	{
		printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
		ShowCerts(ssl);  /* get any certs */
		while (1)
		{
			char p[100];
			printf("please input sned msg: ");
			gets(p);
			printf("strlen:%d,%s\n", strlen(p), p);
			SSL_write(ssl, p, strlen(p));   /* encrypt & send message */
			bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
			if (bytes >= 0)
			{
				buf[bytes] = '\0';
				printf("Received: \"%s\"\n", buf);
			}
			else 
			{
				SSL_ERROR_WANT_READ;
				int error = SSL_get_error(ssl, bytes);
				printf("error:%d\n", error);
				break;
			}
			
		}
		SSL_shutdown(ssl);
		SSL_free(ssl);        /* release connection state */
	}

	SSL_CTX_free(ctx);        /* release context */
	getchar();
	return 0;
}

服务器端代码

#include <errno.h>
#include <malloc.h>
#include <string.h>
# include <winsock2.h>
# include <ws2tcpip.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

#ifdef  __cplusplus
extern "C" {
#endif
#include "openssl/applink.c"
#ifdef  __cplusplus
}
#endif

#define FAIL    -1
#pragma comment(lib, "Ws2_32.lib")

int OpenListener(WORD port)
{
	SOCKET  m_socket;

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &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;
	}

	m_socket = socket(AF_INET, SOCK_STREAM, 0);

	if (m_socket == INVALID_SOCKET)
	{
		printf("Error at socket(): %ld\n", WSAGetLastError());
		WSACleanup();
		return 0;
	}
	struct sockaddr_in sain;
	//bzero(&addr, sizeof(addr));
	sain.sin_family = AF_INET;
	sain.sin_port = htons(port);
	sain.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (bind(m_socket, (struct sockaddr*)&sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
	{
		perror("can't bind port");
		//abort();
	}
	if (listen(m_socket, 10) != 0)
	{
		perror("Can't configure listening port");
		//abort();
	}
	return m_socket;
}

SSL_CTX* InitServerCTX(void)
{
	SSL_CTX* ctx = NULL;

#if OPENSSL_VERSION_NUMBER >= 0x10000000L
	const SSL_METHOD* method;
#else
	SSL_METHOD* method;
#endif

	SSL_library_init();
	//OpenSSL_add_all_algorithms();  /* load & register all cryptos, etc. */
	SSL_load_error_strings();   /* load all error messages */
	//method = SSLv23_method(); /* create new server-method instance */
	method = SSLv23_server_method();
	ctx = SSL_CTX_new(method);   /* create new context from method */
	if (ctx == NULL)
	{
		ERR_print_errors_fp(stderr);
		abort();
	}
	return ctx;
}

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
	//New lines
	int ret = SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile);
	if (ret != 1)
		ERR_print_errors_fp(stderr);

	if (SSL_CTX_set_default_verify_paths(ctx) != 1)
		ERR_print_errors_fp(stderr);
	//End new lines
	/* set the local certificate from CertFile */
	if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
	{
		ERR_print_errors_fp(stderr);
		//abort();
	}
	/* set the private key from KeyFile (may be the same as CertFile) */
	if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
	{
		ERR_print_errors_fp(stderr);
		abort();
	}
	/* verify private key */
	if (!SSL_CTX_check_private_key(ctx))
	{
		fprintf(stderr, "Private key does not match the public certificate\n");
		abort();
	}
	printf("LoadCertificates success\n");
}

void ShowCerts(SSL* ssl)
{
	X509* cert;
	char* line;

	cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
	if (cert != NULL)
	{
		printf("Server certificates:\n");
		line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
		printf("Subject: %s\n", line);
		free(line);
		line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
		printf("Issuer: %s\n", line);
		free(line);
		X509_free(cert);
	}
	else
		printf("No certificates.\n");
}

void Servlet(SSL* ssl, SOCKET client) /* Serve the connection -- threadable */
{
	char buf[1024];
	char reply[1024];
	int sd, bytes;
	const char* HTMLecho = "hello client";

	ShowCerts(ssl);        /* get any certificates */
	int ret = SSL_accept(ssl);	
	while (1)
	{
		//bytes = recv(client, buf, sizeof(buf), 0);
		bytes = SSL_read(ssl, buf, sizeof(buf)); 
		if (bytes > 0)
		{
			buf[bytes] = '\0';
			printf("Client msg: %s\n", buf);
			sprintf(reply, HTMLecho, buf);   /* construct reply */
			SSL_write(ssl, reply, strlen(reply)); /* send reply */
		}
		else //其他情况
		{
			//printf("read byte < 0\n");
		}
	}
	SSL_shutdown(ssl);
	SSL_free(ssl);
}

int main(int count, char* strings[])
{
	SSL_CTX* ctx;
	SOCKET server;
	char* portnum;
	server = OpenListener(1030);    /* create server socket */

	SSL_library_init();

	portnum = strings[1];
	ctx = InitServerCTX();        /* initialize SSL */
	LoadCertificates(ctx, (char *)"cert.pem", (char *)"key.pem");  /* load certs */

	while (1)
	{
		struct sockaddr_in addr;
		socklen_t len = sizeof(addr);
		SSL* ssl;

		SOCKET client = accept(server, (struct sockaddr*)&addr, &len);  /* accept connection   as usual */

		socklen_t len1;
		struct sockaddr_storage addr1;
		//add1.sin_family = AF_INET;
		char ipstr[INET6_ADDRSTRLEN];
		int port;

		len1 = sizeof addr;
		int r;

		r = getpeername(client, (struct sockaddr*)&addr1, &len1);

		// deal with both IPv4 and IPv6:
		if (addr1.ss_family == AF_INET)
		{
			struct sockaddr_in* s = (struct sockaddr_in*)&addr1;
			port = ntohs(s->sin_port);
			inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
		}
		else
		{ // AF_INET6
			struct sockaddr_in6* s = (struct sockaddr_in6*)&addr1;
			port = ntohs(s->sin6_port);
			inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
		}

		printf("Peer IP address: %s,port:%d\n", ipstr,port);
		ssl = SSL_new(ctx);              /* get new SSL state with context */
		//SSL_set_fd(ssl, client);      /* set connection socket to SSL state */
		BIO* bio = BIO_new_socket(client, BIO_NOCLOSE);
		SSL_set_bio(ssl, bio, bio);

		Servlet(ssl, client);         /* service connection */
	}
	SSL_CTX_free(ctx);         /* release context */
}

总结

可能遇到的问题
1.要确保代码中applink.c文件的存在,否则服务器端代码会提示Unlink的错误
2.服务器端代码要求输入密码,请使用生成秘钥时的密码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值