openssl不能完成双向验证,只能单向验证的问题。

qiankun1993 2015-07-13 12:07:16
前两天做了基于openssl单向验证的文件传输,客户端能正常的检测到服务器端的证书,今天试了一下把单项验证改为双向验证,但是服务器端无论如何都不能检测到客户端的证书,服务器端的SSL_get_peer_certificate ()返回值总是为NULL。

服务器和客户端的证书私钥应该没有问题,都可以分别进行单向验证。

代码如下,各位大侠帮小弟看看哪里有问题,纠结了一上午。。。


//client端代码
#include <openssl/rand.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <errno.h>
#include <curses.h>

#define PORT 443
#define SERVER "127.0.0.1"
#define CACERT "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/cacert.pem"
#define MYCERTF "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/cacert2.pem"
#define MYKEYF "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/privkey2.pem"
#define MSGLENGTH 1024
int
main ()
{
struct sockaddr_in sin;
int seed_int[100];

SSL *ssl;
SSL_METHOD *meth;
SSL_CTX *ctx;

int i;

OpenSSL_add_ssl_algorithms ();
SSL_load_error_strings ();
meth = (SSL_METHOD *) TLSv1_client_method ();
ctx = SSL_CTX_new (meth);
if (NULL == ctx)
exit (1);
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations (ctx, CACERT, NULL);
if (0 == SSL_CTX_use_certificate_file (ctx, MYCERTF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
if (0 == SSL_CTX_use_PrivateKey_file (ctx, MYKEYF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
if (!SSL_CTX_check_private_key (ctx))
{
printf ("Private key does not match the certificate public key/n");
exit (1);
}
srand ((unsigned) time (NULL));
for (i = 0; i < 100; i++)
seed_int[i] = rand ();
RAND_seed (seed_int, sizeof (seed_int));
SSL_CTX_set_cipher_list (ctx, "RC4-MD5");
SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);
int sock;
printf ("Begin tcp socket.../n");
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf ("SOCKET error. /n");
}
memset (&sin, '/0', sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr (SERVER); /* Server IP */
sin.sin_port = htons (PORT); /* Server Port number */
int icnn = connect (sock, (struct sockaddr *) &sin, sizeof (sin));
if (icnn == -1)
{
printf ("can not connect to server,%s/n", strerror (errno));
exit (1);
}
ssl = SSL_new (ctx);
if (NULL == ssl)
exit (1);
if (0 >= SSL_set_fd (ssl, sock))
{
printf ("Attach to Line fail!/n");
exit (1);
}
int k = SSL_connect (ssl);
if (0 == k)
{
printf ("%d/n", k);
printf ("SSL connect fail!/n");
exit (1);
}
printf ("connect to server/n");
char sendmsg[MSGLENGTH] = "/0";
char revmsg[MSGLENGTH] = "/0";
int err = SSL_read (ssl, revmsg, sizeof (revmsg));
revmsg[err] = '/0';
printf ("%s/n", revmsg);
while (1)
{
printf ("please input the data to send:/n");
scanf ("%s", sendmsg);
SSL_write (ssl, sendmsg, strlen (sendmsg));
printf ("send message ' %s ' success/n", sendmsg);
}
SSL_shutdown (ssl);
SSL_free (ssl);
SSL_CTX_free (ctx);
close (sock);
getch ();
return 0;
}





//server 服务器端代码
#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <curses.h>

#define MSGLENGTH 1024
#define PORT 443
#define CACERT "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/cacert2.pem"
#define SVRCERTF "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/cacert.pem"
#define SVRKEYF "/home/test/linux-kernel/SDK-SFSS/SDK-SFSS/OpenSSL/test/privkey.pem"
int
main ()
{
int sock;
SSL_METHOD *meth;
SSL_CTX *ctx;
SSL *ssl;
OpenSSL_add_ssl_algorithms ();
SSL_load_error_strings ();
meth = (SSL_METHOD *) TLSv1_server_method ();
ctx = SSL_CTX_new (meth);
if (NULL == ctx)
exit (1);
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations (ctx, CACERT, NULL);
//载入证书
if (0 == SSL_CTX_use_certificate_file (ctx, SVRCERTF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
//载入私钥
if (0 == SSL_CTX_use_PrivateKey_file (ctx, SVRKEYF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
//验证
if (!SSL_CTX_check_private_key (ctx))
{
printf ("Private key does not match the certificate public key/n");
exit (1);
}
SSL_CTX_set_cipher_list (ctx, "RC4-MD5");
SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);
printf ("Begin tcp socket.../n");
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf ("SOCKET error! /n");
return 0;
}
struct sockaddr_in addr;
memset (&addr, '/0', sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (PORT); /* Server Port number */
addr.sin_addr.s_addr = INADDR_ANY;
int nResult = bind (sock, (struct sockaddr *) &addr, sizeof (addr));
if (nResult == -1)
{
printf ("bind socket error/n");
return 0;
}
printf ("server start successfully,port:%d/nwaiting for connections/n",
PORT);
struct sockaddr_in sa_cli;
int err = listen (sock, 5);
if (-1 == err)
exit (1);
int client_len = sizeof (sa_cli);
int ss = accept (sock, (struct sockaddr *) &sa_cli, &client_len);
if (ss == -1)
{
exit (1);
}
close (sock);
printf ("Connection from %d, port %d/n", sa_cli.sin_addr.s_addr,
sa_cli.sin_port);
ssl = SSL_new (ctx);
if (NULL == ssl)
exit (1);
if (0 == SSL_set_fd (ssl, ss))
{
printf ("Attach to Line fail!/n");
exit (1);
}
int k = SSL_accept (ssl);
if (0 == k)
{
printf ("%d/n", k);
printf ("SSL connect fail!/n");
exit (1);
}
X509 *client_cert;
client_cert = SSL_get_peer_certificate (ssl);
printf ("find to try to connect/n");
if (client_cert != NULL)
{
printf ("Client certificate:/n");
char *str =
X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
if (NULL == str)
{
printf ("auth error!/n");
exit (1);
}
printf ("subject: %s/n", str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
if (NULL == str)
{
printf ("certificate name is null/n");
exit (1);
}
printf ("issuer: %s/n", str);
printf ("connect successfully/n");
X509_free (client_cert);
OPENSSL_free (str);
}
else
{
printf ("can not find the customer's certificate/n");
exit (1);
}
char buf[MSGLENGTH];
SSL_write (ssl, "Server is connect to you!/n",
strlen ("Server is connect to you!/n"));
printf ("Listen to the client: /n");
while (1)
{
err = SSL_read (ssl, buf, sizeof (buf));
buf[err] = '/0';
printf ("%s/n", buf);
}
SSL_shutdown (ssl);
SSL_free (ssl);
SSL_CTX_free (ctx);
getch ();
return 0;
}

...全文
1089 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
大家使用openssl的目的无非就是这三个方面了,1、密码学计算,什么RSA加密解密 ,RSA签名,AES,DES啥啥啥的, 2、生成证书,在写这个源码之前,不仅仅是 易语言 届,包括绝大多数需要自签名证书的,都是调用openssl的命令行,全局操作,想要调用API动态申请证书,签署证书的,源码在百度上基本找不到,要翻出去找谷歌,所以我认为至少在易语言范围内,此源码属于首发 3、SSL通讯,这类源码在论坛上不少了,2010年之前东灿大神就发过,他的源码也是我开始学习openssl第一部教程,不过可惜的是论坛上几乎所有openssl通讯源码都或多或少有点问题,基本上没法用于生产环境,所以这次改写了一下,也是翻了不少资料 本套源码特点: 1、几乎是一网打尽所有需要试用openssl的场合,个人认为很有收藏价值,以后基本不需要再去找跟openssl有关的东西了 2、本源码是面向生产环境的,几乎每个子程序,每种应用都考虑到了效率和稳定性,以及内存泄露等诸多问题,拿去之后基本上不需要再修改什么了,要做什么项目直接拿来用就是了 3、着重谈一下SSL通讯,其实在半年前已经重写好了,并且投入了生产环境,目前我3个HTTPS服务器都是用的这套源码,创新之处在于, ? ?? ? A:结合cdecl 壳,让openssl可以调用易语言子程序,进行上锁解锁操作,没有锁的openssl是根本无法想象的,加锁以后,多线程随便跑 ? ?? ? B:SSL_accept 和 SSL_connect 的异步调用,这个东西研究的人很少,网上的源码基本都是同步调用,同步调用的弊端是一旦连接丢失了,就会一直卡在那,而异步调用不会存在这个问题 ? ?? ? C:完整的证书验证机制,回调验证,可做双向验证通讯 4、关于证书操作部分,随着计算机计算能力的发展,以及苹果宣布逐渐淘汰不是用https的应用程序,安全证书的需求猛增,去颁发机构买一个证书固然省事,但是随便一个证书都是几千块钱一年,并且还不能向下签发给用户,目前像阿里,TX那样的大牛也都开始在用自签名证书,然后向他们的用户发放个人证书,这是一个趋势,作为易语言编程者来说,给自己的用户的软件签发一个个人证书,倒也是一个不错的防破J防抓包方法,目前市面上基本上所有的抓包软件都是只能单向验证的HTTP明文,如果你在软件里强行验证服务器证书,并且服务器强行验证客户证书,那抓包软件再牛也没辙,破J起来难度就更大了,本源码证书操作都是用API操作,支持多线程,可以做简易的证书签发服务器 5、密码学计算部分相比我以前发的那个源码新增了一些东西,修改了一些不合理的机制,使用起来更舒服了,具体可以自己看源码
课程简介    随着”新基建“的推行,其中涉及到的工业互联网、物联网、人工智能、云计算、区块链,无一不是与安全相关,所有数据的存储、传输、签名认证都涉及到密码学技术,所以在这样的大环境下再结合我多年安全开发经验,设计出这门课程。    因为密码学技术在新基建中的重要性,所以使其成为底层开发人员所必备的技能。特别是现在的区块链技术是全面应用密码学,大数据技术和人工智能技术也要解决隐私安全问题。所以现在学习相关技术是非常必要的技术储备,并且可以改造现有的系统,提升其安全性。课程学习目标了解DES算法原理VS2019创建C++项目,并导入openssl库学会OpenSSL DES算法加解密接口加密文件并做PKCS7 Padding 数据填充解密数据并做数据填充解析课程特点    面向工程应用    市面上的一些密码学课程和密码学的书籍,很多都是从考证出发,讲解算法原理并不面向工程应用,而我们现在缺少的是工程应用相关的知识,本课程从工程应用出发,每种技术都主要讲解其在工程中的使用,并演示工程应用的代码。    从零实现部分算法    课程中实现了base16编解码 ,XOR对称加解密算法,PKCS7 pading数据填充算法,通过对一些简单算法的实现,从而加深对密码学的理解。    理论与实践结合    课程如果只是讲代码,同学并不能理解接口背后的原理,在项目设计中就会留下隐患,出现错误也不容易排查出问题。    如果只讲理论,比如对密码学的一些研究,对于大部分从事工程应用的同学并没有必要,而是理论与实践结合,一切为了工程实践。    代码现场打出    代码不放在ppt而是现场打出,更好的让学员理解代码编写的逻辑,老师现场敲出代码正是展示出了工程项目的思考,每个步骤为什么要这么做,考虑了哪些异常,    易学不枯燥    课程为了确保大部分人开发者都学得会,理解算法原理(才能真正理解算法特性),学会工程应用(接口调用,但不局限接口调用,理解接口背后的机制,并能解决工程中会出现的问题),阅读算法源码但不实现密码算法,,并能将密码学投入到实际工程中,如果是想学习具体的加密算法实现,请关注我后面的课程。课程用到的技术    课程主要演示基于 VS2019 C++,部分演示基于ubuntu 18.04 GCC makefile    如果没有装linux系统,对本课程的学习也没有影响    课程中的OpenSSL基于最新的3.0版本,如果是openss 1.1.1版本也支持,再低的版本不支持国密算法。 课程常见问题课程讲解用的什么平台和工具?    课程演示主要在windows,基于VS2019 ,一些项目会移植到Linux在ubuntu18.04上我不会Linux能否学习本门课程?    可以的,课程主要在Windows上,Linux部分只是移植,可以暂时跳过,熟悉了Linux再过来看我不会C/C++ 语言是否能学习本门课程?    至少要会C语言,C++特性用得不多,但做了一个封装,可以预习一些C++基础。会不会讲算法实现,会不会太难学不会?    课程偏工程应用,具体的AES,椭圆曲线、RSA等算法只通过图示讲原理,一些简单hash算法会读一些源码,并不去实现,课程中会单独实现简洁的XOR对称加密和base16算法(代码量不大易懂)。其他的应用我们都基于OpenSSL3.0的SDK调用算法。课程提供源码和PPT吗?    课程中所有讲解的源码都提供,课程的上课的ppt也提供,PPT提供pdf版,只可以用于学习,不得商用,代码可以用于商用软件项目,涉及到开源系统部分,需要遵守开源的协议,但不得用于网络教学。要观看全部内容请点击c++实战区块链核心密码学-基于opensslhttps://edu.csdn.net/course/play/29593

4,450

社区成员

发帖
与我相关
我的任务
社区描述
云计算 云安全相关讨论
社区管理员
  • 云安全社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧