一、生成证书
openSSL生成RSA证书
1 生成自签CA

生成CA密钥
genrsa -aes256 -passout pass:123456 -out ca_rsa_private.pem 2048
1
自签名证书
req -new -key server_rsa_private.pem -passin pass:server -out server.csr
1
2 生成服务端证书

生成服务端密钥
genrsa -aes256 -passout pass:server -out server_rsa_private.pem 2048
1
生成服务端代签名证书
req -new -key server_rsa_private.pem -passin pass:server -out server.csr
1
使用CA证书及密钥对服务器证书进行签名
x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
1
3 生成客户端证书

生成客户端密钥
genrsa -aes256 -passout pass:client -out client_rsa_private.pem 2048
1
生成客户端代签名证书
req -new -key client_rsa_private.pem -passin pass:client -out client.csr
1
使用CA证书及密钥对客户端证书进行签名
x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out client.crt
1
openSSL生成SM2证书
1 生成自签CA
生成CA密钥
ecparam -genkey -name SM2 -out ca.key
1
自签名证书
req -new -x509 -days 3650 -key ca.key -out ca.crt
1
这里ecdsa with sha256可能需要换成sm3,不过在RFC 5349中规定为ecdsa SHA做digest,所以需要做二次开发,这次暂时用这个.
2 生成服务端证书

生成服务端密钥
ecparam -genkey -name SM2 -out server_sm2_private.pem
1
生成服务端代签名证书
req -new -key server_sm2_private.pem -out server.csr
1
使用CA证书及密钥对服务器证书进行签名
x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
1
3 生成客户端证书

生成客户端密钥
ecparam -genkey -name SM2 -out client_sm2_private.pem
1
生成客户端代签名证书
req -new -key client_sm2_private.pem -out client.csr
1
使用CA证书及密钥对客户端证书进行签名
x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
1
生成ECC证书
和SM2大同小异,SM2也是ECC改造的国密算法。

1 生成自签CA
生成CA密钥
ecparam -genkey -name prime256v1 -out ca.key
1
自签名证书
req -new -x509 -days 3650 -key ca.key -out ca.crt
1
2 生成服务端证书

生成服务端密钥
ecparam -genkey -name prime256v1 -out server_ecc_private.pem
1
生成服务端代签名证书
req -new -key server_ecc_private.pem -out server.csr
1
使用CA证书及密钥对服务器证书进行签名
x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
1
3 生成客户端证书

生成客户端密钥
ecparam -genkey -name prime256v1 -out client_ecc_private.pem
1
生成客户端代签名证书
req -new -key client_ecc_private.pem -out client.csr
1
使用CA证书及密钥对客户端证书进行签名
x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
1
证书项
C-----国家(Country Name)
ST----省份(State or Province Name)
L----城市(Locality Name)
O----公司(Organization Name)
OU----部门(Organizational Unit Name)
CN----产品名(Common Name)
emailAddress----邮箱(Email Address)

二、身份认证
Server代码:

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <winsock2.h>
#include<ws2tcpip.h>
#include <tchar.h>
#include <io.h>
#include <process.h>
#include <windows.h>
#include <openssl/ssl.h>
#include <openssl/ssl2.h>
#include <openssl/ssl3.h>
#include <openssl/err.h>
#pragma warning(disable:4996)
#define MAXBUF 1024
char caCertFilePath[MAX_PATH]={}; //ca证书路径
char serverCertFilePath[MAX_PATH]={}; //服务端证书路径
char serverPrivateFilePath[MAX_PATH]={}; //服务端私钥路径 void ShowCerts(SSL * ssl)
{
X509 *cert;
char *line; cert = SSL_get_peer_certificate(ssl);
// SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
// 如果验证不通过,那么程序抛出异常中止连接
if(SSL_get_verify_result(ssl) == X509_V_OK){
printf("证书验证通过\n");
}
if (cert != NULL) {
printf("数字证书信息:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), , );
printf("证书: %s\n", line);
//free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), , );
printf("颁发者: %s\n", line);
//free(line);
X509_free(cert);
} else
printf("无证书信息!\n");
}
void Two_Auth()
{
int sockfd, new_fd;
socklen_t len;
struct sockaddr_in my_addr, their_addr;
unsigned int myport, lisnum;
char buf[MAXBUF + ];
SSL_CTX *ctx; //if (argv[1])
// myport = atoi(argv[1]);
//else
myport = ; //if (argv[2])
// lisnum = atoi(argv[2]);
//else
lisnum = ; /* SSL 库初始化 */
SSL_library_init();
/* 载入所有 SSL 算法 */
OpenSSL_add_all_algorithms();
/* 载入所有 SSL 错误消息 */
SSL_load_error_strings();
/* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
ctx = SSL_CTX_new(SSLv23_server_method());
/* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
} // 双向验证
// SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
// SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// 设置信任根证书
if (SSL_CTX_load_verify_locations(ctx, caCertFilePath,NULL)<=){
ERR_print_errors_fp(stdout);
system("pause");
exit();
} /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
/*FILE *caf=fopen("../file/server.crt","r");
char bufStr[5000]={0};
fread(bufStr,1,5000,caf);
fclose(caf);*/
if (SSL_CTX_use_certificate_file(ctx, serverCertFilePath, SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
/* 载入用户私钥 */
/*memset(bufStr,0,5000);
FILE *prif=fopen("../file/server_rsa_private.pem.unsecure","r");
fread(bufStr,1,5000,prif);
fclose(prif);*/
if (SSL_CTX_use_PrivateKey_file(ctx,serverPrivateFilePath, SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
exit();
}
/* 检查用户私钥是否正确 */
if (!SSL_CTX_check_private_key(ctx)) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
WSADATA wsd;
int resStartup = WSAStartup(MAKEWORD(,),&wsd);
if( != resStartup)
{
printf("failed to WSAStartup!\n");
system("pause");
exit();
}
/* 开启一个 socket 监听 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) == - ) {
perror("socket");
system("pause");
exit();
} else
printf("socket created\n");
memset(&my_addr,,sizeof(my_addr));
//bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
== -) {
perror("bind");
system("pause");
exit();
} else
printf("binded\n"); if (listen(sockfd, lisnum) == -) {
perror("listen");
system("pause");
exit();
} else
printf("begin listen\n"); while () {
SSL *ssl;
len = sizeof(struct sockaddr);
/* 等待客户端连上来 */
if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len))
== -) {
perror("accept");
system("pause");
exit(errno);
} else
printf("server: got connection from %s, port %d, socket %d\n",
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port),
new_fd); /* 基于 ctx 产生一个新的 SSL */
ssl = SSL_new(ctx);
/* 将连接用户的 socket 加入到 SSL */
SSL_set_fd(ssl, new_fd);
/* 建立 SSL 连接 */
if (SSL_accept(ssl) == -) {
perror("accept");
close(new_fd);
system("pause");
break;
}
ShowCerts(ssl); /* 开始处理每个新连接上的数据收发 */
//bzero(buf, MAXBUF + 1);
memset(buf,,MAXBUF + );
strcpy(buf, "server->client");
/* 发消息给客户端 */
len = SSL_write(ssl, buf, strlen(buf)); if (len <= ) {
printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno,
strerror(errno));
goto finish;
} else
printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len); memset(buf,, MAXBUF + );
/* 接收客户端的消息 */
len = SSL_read(ssl, buf, MAXBUF);
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
else
printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
/* 处理每个新连接上的数据收发结束 */
finish:
/* 关闭 SSL 连接 */
SSL_shutdown(ssl);
/* 释放 SSL */
SSL_free(ssl);
/* 关闭 socket */
//close(new_fd);
WSACleanup();
}
/* 关闭监听的 socket */
close(sockfd);
/* 释放 CTX */
SSL_CTX_free(ctx);
WSACleanup();
}
void One_Auth()
{
int sockfd=, new_fd=;
socklen_t len=;
struct sockaddr_in my_addr, their_addr;
unsigned int myport, lisnum;
char buf[MAXBUF + ]={};
SSL_CTX *ctx; //if (argv[1])
// myport = atoi(argv[1]);
//else
myport = ; //if (argv[2])
// lisnum = atoi(argv[2]);
//else
lisnum = ; /* SSL 库初始化 */
SSL_library_init();
/* 载入所有 SSL 算法 */
OpenSSL_add_all_algorithms();
/* 载入所有 SSL 错误消息 */
SSL_load_error_strings();
/* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
ctx = SSL_CTX_new(SSLv23_server_method());
/* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
} // 单向验证
// SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
// SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// 设置信任根证书
/*if (SSL_CTX_load_verify_locations(ctx, "../file/ca.crt",NULL)<=0){
ERR_print_errors_fp(stdout);
system("pause");
exit(1);
}*/ /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
/*FILE *caf=fopen("../file/server.crt","r");
char bufStr[5000]={0};
fread(bufStr,1,5000,caf);
fclose(caf);*/
if (SSL_CTX_use_certificate_file(ctx, serverCertFilePath, SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
/* 载入用户私钥 */
/*memset(bufStr,0,5000);
FILE *prif=fopen("../file/server_rsa_private.pem.unsecure","r");
fread(bufStr,1,5000,prif);
fclose(prif);*/
if (SSL_CTX_use_PrivateKey_file(ctx,serverPrivateFilePath , SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
exit();
}
/* 检查用户私钥是否正确 */
if (!SSL_CTX_check_private_key(ctx)) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
WSADATA wsd;
int resStartup = WSAStartup(MAKEWORD(,),&wsd);
if( != resStartup)
{
printf("failed to WSAStartup!\n");
system("pause");
exit();
}
/* 开启一个 socket 监听 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) == - ) {
perror("socket");
system("pause");
exit();
} else
printf("socket created\n");
memset(&my_addr,,sizeof(my_addr));
//bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
== -) {
perror("bind");
system("pause");
exit();
} else
printf("binded\n"); if (listen(sockfd, lisnum) == -) {
perror("listen");
system("pause");
exit();
} else
printf("begin listen\n"); while () {
SSL *ssl;
len = sizeof(struct sockaddr);
/* 等待客户端连上来 */
if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len))== -) {
perror("accept");
system("pause");
exit(errno);
} else
printf("server: got connection from %s, port %d, socket %d\n",
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port),new_fd); /* 基于 ctx 产生一个新的 SSL */
ssl = SSL_new(ctx);
/* 将连接用户的 socket 加入到 SSL */
SSL_set_fd(ssl, new_fd);
/* 建立 SSL 连接 */
if (SSL_accept(ssl) == -) {
perror("accept");
close(new_fd);
system("pause");
break;
}
ShowCerts(ssl); /* 开始处理每个新连接上的数据收发 */
//bzero(buf, MAXBUF + 1);
memset(buf,,MAXBUF + );
strcpy(buf, "server->client");
/* 发消息给客户端 */
len = SSL_write(ssl, buf, strlen(buf)); if (len <= ) {
printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno,
strerror(errno));
goto finish;
} else
printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len); memset(buf,, MAXBUF + );
/* 接收客户端的消息 */
len = SSL_read(ssl, buf, MAXBUF);
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
else
printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
/* 处理每个新连接上的数据收发结束 */
finish:
/* 关闭 SSL 连接 */
SSL_shutdown(ssl);
/* 释放 SSL */
SSL_free(ssl);
/* 关闭 socket */
//close(new_fd);
WSACleanup();
}
/* 关闭监听的 socket */
close(sockfd);
/* 释放 CTX */
SSL_CTX_free(ctx);
WSACleanup();
}
int _tmain(int argc, _TCHAR* argv[]) { int alogType=-;
printf("服务端---请选择算法:\n");
printf("1:RSA 2:SM2\n");
scanf("%d",&alogType);
if (alogType==)
{
char *rsaCaCertFile="../file/ca.crt";
char *rsaServerCertFile="../file/server.crt";
char *rsaServerPrivateFile="../file/server_rsa_private.pem.unsecure";
strcpy(caCertFilePath,rsaCaCertFile);
strcpy(serverCertFilePath,rsaServerCertFile);
strcpy(serverPrivateFilePath,rsaServerPrivateFile);
}
else if (alogType==)
{
char *sm2CaCertFile="../SM2_Cert/ca.crt";
char *sm2ServerCertFile="../SM2_Cert/server.crt";
char *sm2ServerPrivateFile="../SM2_Cert/server_sm2_private.pem";
strcpy(caCertFilePath,sm2CaCertFile);
strcpy(serverCertFilePath,sm2ServerCertFile);
strcpy(serverPrivateFilePath,sm2ServerPrivateFile);
} int type=-;
printf("服务端----请选择认证方式:\n");
printf("1:单向认证 2:双向认证\n");
scanf("%d",&type);
switch (type)
{
case : One_Auth();break;
case : Two_Auth();break;
default:
break;
}
system("pause");
return ;
}

Client代码:

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <winsock2.h>
#include<ws2tcpip.h>
#include <winsock.h>
#include <io.h>
#include <process.h>
#include <windows.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#pragma warning(disable:4996)
#define MAXBUF 1024
char caCertFilePath[MAX_PATH]={}; //ca证书路径
char clientCertFilePath[MAX_PATH]={}; //服务端证书路径
char clientPrivateFilePath[MAX_PATH]={}; //服务端私钥路径 void ShowCerts(SSL * ssl)
{
X509 *cert;
char *line; cert = SSL_get_peer_certificate(ssl);
// SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
// 如果验证不通过,那么程序抛出异常中止连接
if(SSL_get_verify_result(ssl) == X509_V_OK){
printf("证书验证通过\n");
}
if (cert != NULL) {
printf("数字证书信息:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), , );
printf("证书: %s\n", line);
//free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), , );
printf("颁发者: %s\n", line);
//free(line);
X509_free(cert);
} else
printf("无证书信息!\n");
}
void Auth_Two()
{
int sockfd, len;
struct sockaddr_in dest;
char buffer[MAXBUF + ];
SSL_CTX *ctx;
SSL *ssl;
unsigned int myport;
char *myip="127.0.0.1";
myport=; /*if (argc != 5) {
printf("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个"
"IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",
argv[0], argv[0]);
system("pause");
exit(0);
}*/ /* SSL 库初始化,参看 ssl-server.c 代码 */
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
} // 双向验证
// SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
// SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// 设置信任根证书
if (SSL_CTX_load_verify_locations(ctx, caCertFilePath,NULL)<=){
ERR_print_errors_fp(stdout);
system("pause");
exit();
} /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
/* FILE *clientf=fopen("../file/client.crt","r");
char bufStr[5000]={0};
fread(bufStr,1,5000,clientf);
fclose(clientf);*/
if (SSL_CTX_use_certificate_file(ctx, clientCertFilePath, SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
/* 载入用户私钥 */
/*FILE *clientRsaf=fopen("../file/client_rsa_private.pem.unsecure","r");
memset(bufStr,0,5000);
fread(bufStr,1,5000,clientRsaf);
fclose(clientRsaf);*/
if (SSL_CTX_use_PrivateKey_file(ctx, clientPrivateFilePath, SSL_FILETYPE_PEM) <= ) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
/* 检查用户私钥是否正确 */
if (!SSL_CTX_check_private_key(ctx)) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
}
WSADATA wsd;
int resStartup = WSAStartup(MAKEWORD(,),&wsd);
if( != resStartup)
{
printf("failed to WSAStartup!\n");
system("pause");
exit();
}
/* 创建一个 socket 用于 tcp 通信 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) < ) {
perror("Socket");
system("pause");
exit(errno);
}
printf("socket created\n"); /* 初始化服务器端(对方)的地址和端口信息 */
//bzero(&dest, sizeof(dest));
memset(&dest,,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(myport); unsigned long l1=;
l1=inet_addr(myip);
in_addr addr1;
memcpy(&addr1, &l1, );
if (inet_ntoa(addr1) == ) {
perror(myip);
system("pause");
exit(errno);
}
dest.sin_addr=addr1;
printf("address created\n"); /* 连接服务器 */
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != ) {
perror("Connect ");
system("pause");
exit(errno);
}
printf("server connected\n"); /* 基于 ctx 产生一个新的 SSL */
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sockfd);
/* 建立 SSL 连接 */
if (SSL_connect(ssl) == -)
ERR_print_errors_fp(stderr);
else {
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl);
} /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
memset(buffer,, MAXBUF + );
/* 接收服务器来的消息 */
len = SSL_read(ssl, buffer, MAXBUF);
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据\n",
buffer, len);
else {
printf
("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
goto finish;
}
memset(buffer,, MAXBUF + );
strcpy(buffer, "from client->server");
/* 发消息给服务器 */
len = SSL_write(ssl, buffer, strlen(buffer));
if (len < )
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
buffer, errno, strerror(errno));
else
printf("消息'%s'发送成功,共发送了%d个字节!\n",
buffer, len); finish:
/* 关闭连接 */
SSL_shutdown(ssl);
SSL_free(ssl);
//close(sockfd);
SSL_CTX_free(ctx);
WSACleanup();
}
void Auth_One()
{
int sockfd, len;
struct sockaddr_in dest;
char buffer[MAXBUF + ];
SSL_CTX *ctx;
SSL *ssl;
unsigned int myport;
char *myip="127.0.0.1";
myport=; /*if (argc != 5) {
printf("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个"
"IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",
argv[0], argv[0]);
system("pause");
exit(0);
}*/ /* SSL 库初始化,参看 ssl-server.c 代码 */
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_method());
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
system("pause");
exit();
} // 单向验证
/*// SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
// SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// 设置信任根证书
if (SSL_CTX_load_verify_locations(ctx,rsaCaCertFile,NULL)<=0){
ERR_print_errors_fp(stdout);
system("pause");
exit(1);
} /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 * /
if (SSL_CTX_use_certificate_file(ctx, rsaServerCertFile, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stdout);
system("pause");
exit(1);
}
/* 载入用户私钥 * /
if (SSL_CTX_use_PrivateKey_file(ctx, clientPrivateFilePath, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stdout);
system("pause");
exit(1);
}
/* 检查用户私钥是否正确 * /
if (!SSL_CTX_check_private_key(ctx)) {
ERR_print_errors_fp(stdout);
system("pause");
exit(1);
}*/
WSADATA wsd;
int resStartup = WSAStartup(MAKEWORD(,),&wsd);
if( != resStartup)
{
printf("failed to WSAStartup!\n");
system("pause");
exit();
}
/* 创建一个 socket 用于 tcp 通信 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) < ) {
perror("Socket");
system("pause");
exit(errno);
}
printf("socket created\n"); /* 初始化服务器端(对方)的地址和端口信息 */
//bzero(&dest, sizeof(dest));
memset(&dest,,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(myport); unsigned long l1=;
l1=inet_addr(myip);
in_addr addr1;
memcpy(&addr1, &l1, );
if (inet_ntoa(addr1) == ) {
perror(myip);
system("pause");
exit(errno);
}
dest.sin_addr=addr1;
printf("address created\n"); /* 连接服务器 */
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != ) {
perror("Connect ");
system("pause");
exit(errno);
}
printf("server connected\n"); /* 基于 ctx 产生一个新的 SSL */
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sockfd);
/* 建立 SSL 连接 */
if (SSL_connect(ssl) == -)
ERR_print_errors_fp(stderr);
else {
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl);
} /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
memset(buffer,, MAXBUF + );
/* 接收服务器来的消息 */
len = SSL_read(ssl, buffer, MAXBUF);
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据\n",
buffer, len);
else {
printf
("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
goto finish;
}
memset(buffer,, MAXBUF + );
strcpy(buffer, "from client->server");
/* 发消息给服务器 */
len = SSL_write(ssl, buffer, strlen(buffer));
if (len < )
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
buffer, errno, strerror(errno));
else
printf("消息'%s'发送成功,共发送了%d个字节!\n",
buffer, len); finish:
/* 关闭连接 */
SSL_shutdown(ssl);
SSL_free(ssl);
//close(sockfd);
SSL_CTX_free(ctx);
WSACleanup();
}
int _tmain(int argc, _TCHAR* argv[])
{
int alogType=-;
printf("客户端---请选择算法:\n");
printf("1:RSA 2:SM2\n");
scanf("%d",&alogType);
if (alogType==)
{
char *rsaCaCertFile="../file/ca.crt";
char *rsaClientCertFile="../file/client.crt";
char *rsaClientPrivateFile="../file/client_rsa_private.pem.unsecure";
strcpy(caCertFilePath,rsaCaCertFile);
strcpy(clientCertFilePath,rsaClientCertFile);
strcpy(clientPrivateFilePath,rsaClientPrivateFile);
}
else if (alogType==)
{
char *sm2CaCertFile="../SM2_Cert/ca.crt";
char *sm2ClientCertFile="../SM2_Cert/client.crt";
char *sm2ClientPrivateFile="../SM2_Cert/client_sm2_private.pem";
strcpy(caCertFilePath,sm2CaCertFile);
strcpy(clientCertFilePath,sm2ClientCertFile);
strcpy(clientPrivateFilePath,sm2ClientPrivateFile);
}
int type=-;
printf("客户端----请选择认证方式:\n");
printf("1:单向认证 2:双向认证\n");
scanf("%d",&type);
switch (type)
{
case : Auth_One();break;
case : Auth_Two();break;
default:
break;
}
system("pause");
return ;
}

以上代码RSA和ECC都测试通过了,但是SM2测试时候报错了。

45444:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl\record\rec_layer_s3.c:1528:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 311 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
error in s_client

以上是用命令行进行身份认证时报的错误信息,用上述的代码测试同样会报此类错误信息,在握手的时候直接崩溃

45444:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl\record\rec_layer_s3.c:1528:SSL alert number 40

  

应该是openssl1.1.1和1.1.1a都是这样的错误,通过抓包可以看到客户端和服务端在握手的时候使用TLS版本不一致


  

一个是TLS1.2一个是TLS1.3,个人感觉是因为不能识别证书,导致降低了TLS版本,从而不能握手成功,不知道这个是不是openssl1.1.1没有完善的地方,后续如果解决了会及时更新。

提供一个完善的代码和文档下载链接,方便大家研究openssl身份认证

下载链接:https://download.csdn.net/download/xuebing1995/10947453

---------------------
原文链接:https://blog.csdn.net/xuebing1995/article/details/86742078

[转载]OpenSSL身份认证 RSA、ECC、SM2的更多相关文章

  1. 基于X.509证书和SSL协议的身份认证过程实现(OpenSSL可以自己产生证书,有TCP通过SSL进行实际安全通讯的实际编程代码)good

    上周帮一个童鞋做一个数字认证的实验,要求是编程实现一个基于X.509证书认证的过程,唉!可怜我那点薄弱的计算机网络安全的知识啊!只得恶补一下了. 首先来看看什么是X.509.所谓X.509其实是一种非 ...

  2. 搭建私有CA并基于OpenSSL实现双向身份认证

    0x00 前言 互联网上的Web应用由于用户数目广泛,都是采用单向身份认证的,只需要客户端验证服务端的身份.但如果是企业内部的应用对接,客户端数量有限,可能就会要求对客户端也做身份验证,这时就需要一个 ...

  3. API网关设计(一)之Token多平台身份认证方案(转载)

    原文:https://segmentfault.com/a/1190000018535570?utm_source=tag-newest 概述 今天咱们面对移动互联网的发展,系统一般是多个客户端对应一 ...

  4. ASP.NET Core 使用外部登陆提供程序登陆的流程,以及身份认证的流程 (转载)

    阅读目录 在Asp.Net Core 中使用外部登陆(google.微博...) 中间件管道 The Authentication Middleware The Challenge 与认证中间件进行交 ...

  5. Asp.net MVC使用FormsAuthentication,MVC和WEB API可以共享身份认证 (转载)

    在实际的项目应用中,很多时候都需要保证数据的安全和可靠,如何来保证数据的安全呢?做法有很多,最常见的就是进行身份验证.验证通过,根据验证过的身份给与对应访问权限.同在Web Api中如何实现身份认证呢 ...

  6. [转载]OpenSSL中文手册之命令行详解(未完待续)

     声明:OpenSSL之命令行详解是根据卢队长发布在https://blog.csdn.net/as3luyuan123/article/details/16105475的系列文章整理修改而成,我自己 ...

  7. 写给开发人员的实用密码学(七)—— 非对称密钥加密算法 RSA/ECC

    本文部分内容翻译自 Practical-Cryptography-for-Developers-Book,笔者补充了密码学历史以及 openssl 命令示例,并重写了 RSA/ECC 算法原理.代码示 ...

  8. [Docker]docker搭建私有仓库(ssl、身份认证)

    docker搭建私有仓库(ssl.身份认证) 环境:CentOS 7.Docker 1.13.1 CentOS 7相关: https://www.cnblogs.com/ttkl/p/11041124 ...

  9. 别无分号只此一家,Python3接入支付宝身份认证接口( alipay.user.certify)体系(2021年最新攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_184 目前国内身份认证体系做的比较不错的大抵就是支付宝和微信两家了,支付宝的身份验证基于支付宝app的实人认证能力,采用多因子认证 ...

随机推荐

  1. IBM公司的面试题,看看你能做出多少。

    进入IBM差不多是每一个IT人的梦想.IBM公司向来以高素质人才作为企业持续竞争力的保证,所以经常出一些千奇百怪的面试题,来考验一个人的综合能力,以下是5道IBM曾经出过的面试题,看看你能作出几道:  ...

  2. setTimeout、Promise、Async/Await 的执行顺序

    问题描述:以下这段代码的执行结果 async function async1() { console.log('async1 start'); await async2(); console.log( ...

  3. CenterOS7中解决No package mysql-server available.

    CenterOS7中解决No package mysql-server available. 1.使用yum install -y mysql-server报错如下: [root@heyong_jd ...

  4. Linux学习--第四天--find、locate、帮助命令、grep、who、w、压缩命令、网络命令、mount

    find 命令格式:find 搜索范围 匹配条件find 搜索范围 匹配条件(搜索范围一定要填写,不写默认为当前文件夹,不包括子文件夹.) find /etc -name init #搜索文件和文件夹 ...

  5. RK3288之kernel目录结构以及功能

    :~/RK3288/kernel$ ls android include MAINTAINERS security arch init Makefile sound backported-featur ...

  6. Linux架构之Nginx 动静分离

    案例No.51:Nginx动静分离 1.web01配置静态资源 [root@web01 ~]# cd /etc/nginx/conf.d/#配置静态资源[root@web01 conf.d]# cat ...

  7. ubuntu安装软件失败

    Unable to fetch some archives, maybe run apt-get update or try with --fix-missing sudo gedit /etc/ho ...

  8. sshfs 挂载远程文件夹

    1 安装 # yum install sshfs # dnf + releases] $ sudo apt-get install sshfs [On Debian/Ubuntu based syst ...

  9. mysql—查询数据库表的数量

    1.查看数据库表数量SELECT count(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA='dbname';  2.获取 ...

  10. Zookeeper学习笔记(下)

    这是ZK学习笔记的下篇, 主要希望可以分享一些 ZK 的应用以及其应用原理 我本人的学习告一段落, 不过还遗留了一些ZK相关的任务开发和性能测试的任务, 留待以后完成之后再通过其他文章来进行分享了 Z ...