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.服务器端代码要求输入密码,请使用生成秘钥时的密码
更多推荐
所有评论(0)