利用openssl实现SSL安全通讯协议(二)

31 篇文章 2 订阅
14 篇文章 12 订阅

Openssl应用编程框架:

1.客户端程序的框架为:

  1. meth = SSLv23_client_method();  
  2. ctx = SSL_CTX_new (meth);  
  3. ssl = SSL_new(ctx);  
  4. fd = socket();  
  5. connect();  
  6. SSL_set_fd(ssl,fd);  
  7. SSL_connect(ssl);  
  8. SSL_write(ssl,"Hello world",strlen("Hello World!"));  

2.服务端程序的框架为:

  1. meth = SSLv23_server_method();  
  2. ctx = SSL_CTX_new (meth);  
  3. ssl = SSL_new(ctx);  
  4. fd = socket();  
  5. bind();  
  6. listen();  
  7. accept();  
  8. SSL_set_fd(ssl,fd);  
  9. SSL_connect(ssl);  
  10. SSL_read (ssl, buf, sizeof(buf));  

对程序来说,openssl将整个握手过程用一对函数体现,即客户端的SSL_connect和服务端的SSL_accept。而后的应用层数据交换则用SSL_read和 SSL_write来完成。

SSL协议一般要用到证书,可以用openssl工具生成:

1、生成RSA密钥的方法 
openssl genrsa -des3 -out privkey.pem 2048 
这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码,如果你不想要每次都输入密码,可以改成: 
openssl genrsa -out privkey.pem 2048 
建议用2048位密钥,少于此可能会不安全或很快将不安全。 

2、生成一个证书请求 
openssl req -new -key privkey.pem -out cert.csr 
这个命令将会生成一个证书请求,当然,用到了前面生成的密钥privkey.pem文件 
这里将生成一个新的文件cert.csr,即一个证书请求文件,你可以拿着这个文件去数字证书颁发机构(即CA)申请一个数字证书。CA会给你一个新的文件cacert.pem,那才是你的数字证书。 

如果是自己做测试,那么证书的申请机构和颁发机构都是自己。就可以用下面这个命令来生成证书: 
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 
这个命令将用上面生成的密钥privkey.pem生成一个数字证书cacert.pem 

3、使用数字证书和密钥 
有了privkey.pem和cacert.pem文件后就可以在自己的程序中使用了。

服务端程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <winsock2.h>


#include <openssl/rsa.h>       /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  HOME "cacert.pem"
#define KEYF   HOME "privkey.pem"


#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }

void socket_init_tcpip()
{
#ifdef _WIN32
	WORD     wVersionRequested;
	WSADATA  wsaData;

	wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData ) != 0)
	{
		return;	
	}
	/* 检查版本号 */
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		return;
	}
#else	
#endif
}

void main ()
{
	int err;
	int listen_sd;
	int sd;
	struct sockaddr_in sa_serv;
	struct sockaddr_in sa_cli;
	size_t client_len;
	SSL_CTX* ctx;
	SSL*     ssl;
	X509*    client_cert;
	char*    str;
	char     buf [4096];
	SSL_METHOD *meth;

	/* SSL preliminaries. We keep the certificate and key with the context. */

	SSL_load_error_strings();
	SSLeay_add_ssl_algorithms();
	meth = (SSL_METHOD *)SSLv23_server_method();
	ctx = SSL_CTX_new (meth);
	if (!ctx) {
		ERR_print_errors_fp(stderr);
		exit(2);
	}

	if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
		ERR_print_errors_fp(stderr);
		exit(3);
	}
	if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
		ERR_print_errors_fp(stderr);
		exit(4);
	}

	if (!SSL_CTX_check_private_key(ctx)) {
		fprintf(stderr,"Private key does not match the certificate public key\n");
		exit(5);
	}

	/* ----------------------------------------------- */
	/* Prepare TCP socket for receiving connections */
	socket_init_tcpip();
	listen_sd = socket (AF_INET, SOCK_STREAM, 0);   
	CHK_ERR(listen_sd, "socket");

	memset (&sa_serv, '\0', sizeof(sa_serv));
	sa_serv.sin_family      = AF_INET;
	sa_serv.sin_addr.s_addr = INADDR_ANY;
	sa_serv.sin_port        = htons (1111);          /* Server Port number */

	err = bind(listen_sd, (struct sockaddr*) &sa_serv,
		sizeof (sa_serv));                   CHK_ERR(err, "bind");

	/* Receive a TCP connection. */

	err = listen (listen_sd, 5);                    CHK_ERR(err, "listen");

	client_len = sizeof(sa_cli);
	sd = accept (listen_sd, (struct sockaddr*) &sa_cli, (int*)&client_len);
	CHK_ERR(sd, "accept");
	closesocket (listen_sd);

	printf ("Connection from %lx, port %x\n",
		sa_cli.sin_addr.s_addr, sa_cli.sin_port);

	/* ----------------------------------------------- */
	/* TCP connection is ready. Do server side SSL. */

	ssl = SSL_new (ctx);                           CHK_NULL(ssl);
	SSL_set_fd (ssl, sd);
	err = SSL_accept (ssl);                        CHK_SSL(err);

	/* Get the cipher - opt */

	printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

	/* Get client's certificate (note: beware of dynamic allocation) - opt */

	client_cert = SSL_get_peer_certificate (ssl);
	if (client_cert != NULL) {
		printf ("Client certificate:\n");

		str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
		CHK_NULL(str);
		printf ("\t subject: %s\n", str);
		OPENSSL_free (str);

		str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
		CHK_NULL(str);
		printf ("\t issuer: %s\n", str);
		OPENSSL_free (str);

		/* We could do all sorts of certificate verification stuff here before
		deallocating the certificate. */

		X509_free (client_cert);
	} else
		printf ("Client does not have certificate.\n");

	/* DATA EXCHANGE - Receive message and send reply. */
	while(true)
	{
		err = SSL_read (ssl, buf, sizeof(buf) - 1);                   
		CHK_SSL(err);
		buf[err] = '\0';
		printf ("Got %d chars:'%s'\n", err, buf);

		err = SSL_write (ssl, "I hear you.", strlen("I hear you."));  CHK_SSL(err);
	}
	
	/* Clean up. */

	closesocket(sd);
	SSL_free (ssl);
	SSL_CTX_free (ctx);
}

客户端程序代码:

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <WinSock2.h>

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  HOME "cacert_client.pem"
#define KEYF   HOME "privkey.pem"


#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }

void socket_init_tcpip()
{
#ifdef _WIN32
	WORD     wVersionRequested;
	WSADATA  wsaData;

	wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData ) != 0)
	{
		return;	
	}
	/* 检查版本号 */
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		return;
	}
#else	
#endif
}

void main ()
{
	int err=0;
	int sd;
	struct sockaddr_in sa;
	SSL_CTX* ctx;
	SSL*     ssl;
	X509*    server_cert;
	char*    str;
	char     buf [4096];
	SSL_METHOD *meth;

	SSLeay_add_ssl_algorithms();
	meth = (SSL_METHOD *)SSLv23_client_method();
	SSL_load_error_strings();
	ctx = SSL_CTX_new (meth);                        CHK_NULL(ctx);

	CHK_SSL(err);

	if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) 
	{
		ERR_print_errors_fp(stderr);
		exit(3);
	}
	
	if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) 
	{
		ERR_print_errors_fp(stderr);
		exit(4);
	}

	
	if (!SSL_CTX_check_private_key(ctx)) 
	{
		fprintf(stderr,"Private key does not match the certificate public key\n");
		exit(5);
	}

	/* ----------------------------------------------- */
	/* Create a socket and connect to server using normal socket calls. */
	socket_init_tcpip();
	sd = socket (AF_INET, SOCK_STREAM, 0);       CHK_ERR(sd, "socket");

	memset (&sa, '\0', sizeof(sa));
	sa.sin_family      = AF_INET;
	sa.sin_addr.s_addr = inet_addr ("192.168.2.141");   /* Server IP */
	sa.sin_port        = htons     (1111);          /* Server Port number */

	err = connect(sd, (struct sockaddr*) &sa,
		sizeof(sa));                   CHK_ERR(err, "connect");

	/* ----------------------------------------------- */
	/* Now we have TCP conncetion. Start SSL negotiation. */

	ssl = SSL_new (ctx);
	
	CHK_NULL(ssl);    
	SSL_set_fd (ssl, sd);
	err = SSL_connect (ssl);                     
	CHK_SSL(err);

	/* Following two steps are optional and not required for
	data exchange to be successful. */

	/* Get the cipher - opt */

	printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

	/* Get server's certificate (note: beware of dynamic allocation) - opt */

	server_cert = SSL_get_peer_certificate (ssl);       
	CHK_NULL(server_cert);
	printf ("Server certificate:\n");

	str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
	CHK_NULL(str);
	printf ("\t subject: %s\n", str);
	OPENSSL_free (str);

	str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
	CHK_NULL(str);
	printf ("\t issuer: %s\n", str);
	OPENSSL_free (str);

	/* We could do all sorts of certificate verification stuff here before
	deallocating the certificate. */

	X509_free (server_cert);

	/* --------------------------------------------------- */
	/* DATA EXCHANGE - Send a message and receive a reply. */
	while (1)
	{
		printf("please input the words you want to send to server:\n");
		char sendbuf[512]={0};
		scanf("%s",sendbuf);
		err = SSL_write (ssl, sendbuf, strlen(sendbuf));  
		CHK_SSL(err);

		err = SSL_read (ssl, buf, sizeof(buf) - 1);                     
		CHK_SSL(err);
		buf[err] = '\0';
		printf ("Got %d chars:'%s'\n", err, buf);
	}
	
	SSL_shutdown (ssl);  /* send SSL/TLS close_notify */

	/* Clean up. */

	closesocket (sd);
	SSL_free (ssl);
	SSL_CTX_free (ctx);
}



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于OpenSSL实现安全客户端是一种在网络通信中保障数据传输安全的方法。OpenSSL是一个开源的密码学库,可提供加密、解密、数字签名以及SSL/TLS协议等功能。以下是使用OpenSSL实现安全客户端的一般步骤: 1. 生成密钥对:使用OpenSSL库生成公钥和私钥对。公钥用于加密数据,私钥用于解密数据。 2. 加载证书:将信任的证书加载到客户端中,用于验证服务器的身份。证书可以通过CA机构签署,或者使用自签名证书。 3. 建立安全连接:客户端使用OpenSSL库与服务器建立安全连接。连接可能使用SSL/TLS协议,确保数据传输过程中的加密和身份验证。 4. 加密数据:客户端使用公钥加密要发送给服务器的数据。加密后的数据只能使用私钥解密,确保数据在传输过程中安全。 5. 解密数据:客户端使用私钥解密服务器发送的加密数据,以获取原始数据。 6. 验证服务器:客户端使用加载的证书验证服务器的身份。通过验证服务器的证书,可以确保与合法服务器建立安全连接。 7. 错误处理:客户端使用OpenSSL库的错误处理机制来处理任何错误或异常情况,以保证客户端的稳定性和安全性。 通过使用OpenSSL实现安全客户端,可以保护客户端与服务器之间的通信安全。数据在传输过程中经过加密保护,确保只有合法的接收方可以解密数据。利用证书验证服务器身份,防止中间人攻击和欺骗。同时,OpenSSL库提供一套完整的错误处理机制,使得客户端能够及时处理和修复可能的问题,保证系统的稳定性和安全性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值