概述
一、生成证书
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]={0}; //ca证书路径 char serverCertFilePath[MAX_PATH]={0}; //服务端证书路径 char serverPrivateFilePath[MAX_PATH]={0}; //服务端私钥路径 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), 0, 0); printf("证书: %sn", line); //free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("颁发者: %sn", 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 + 1]; SSL_CTX *ctx; //if (argv[1]) // myport = atoi(argv[1]); //else myport = 7838; //if (argv[2]) // lisnum = atoi(argv[2]); //else lisnum = 1; /* 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(1); } // 双向验证 // 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)<=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) <= 0) { ERR_print_errors_fp(stdout); system("pause"); exit(1); } /* 载入用户私钥 */ /*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) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /* 检查用户私钥是否正确 */ if (!SSL_CTX_check_private_key(ctx)) { ERR_print_errors_fp(stdout); system("pause"); exit(1); } WSADATA wsd; int resStartup = WSAStartup(MAKEWORD(2,2),&wsd); if(0 != resStartup) { printf("failed to WSAStartup!n"); system("pause"); exit(1); } /* 开启一个 socket 监听 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { perror("socket"); system("pause"); exit(1); } else printf("socket createdn"); memset(&my_addr,0,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)) == -1) { perror("bind"); system("pause"); exit(1); } else printf("bindedn"); if (listen(sockfd, lisnum) == -1) { perror("listen"); system("pause"); exit(1); } else printf("begin listenn"); while (1) { SSL *ssl; len = sizeof(struct sockaddr); /* 等待客户端连上来 */ if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) { perror("accept"); system("pause"); exit(errno); } else printf("server: got connection from %s, port %d, socket %dn", 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) == -1) { perror("accept"); close(new_fd); system("pause"); break; } ShowCerts(ssl); /* 开始处理每个新连接上的数据收发 */ //bzero(buf, MAXBUF + 1); memset(buf,0,MAXBUF + 1); strcpy(buf, "server->client"); /* 发消息给客户端 */ len = SSL_write(ssl, buf, strlen(buf)); if (len <= 0) { printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'n", buf, errno, strerror(errno)); goto finish; } else printf("消息'%s'发送成功,共发送了%d个字节!n", buf, len); memset(buf,0, MAXBUF + 1); /* 接收客户端的消息 */ len = SSL_read(ssl, buf, MAXBUF); if (len > 0) 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=0, new_fd=0; socklen_t len=0; struct sockaddr_in my_addr, their_addr; unsigned int myport, lisnum; char buf[MAXBUF + 1]={0}; SSL_CTX *ctx; //if (argv[1]) // myport = atoi(argv[1]); //else myport = 7838; //if (argv[2]) // lisnum = atoi(argv[2]); //else lisnum = 1; /* 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(1); } // 单向验证 // 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) <= 0) { ERR_print_errors_fp(stdout); system("pause"); exit(1); } /* 载入用户私钥 */ /*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) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /* 检查用户私钥是否正确 */ if (!SSL_CTX_check_private_key(ctx)) { ERR_print_errors_fp(stdout); system("pause"); exit(1); } WSADATA wsd; int resStartup = WSAStartup(MAKEWORD(2,2),&wsd); if(0 != resStartup) { printf("failed to WSAStartup!n"); system("pause"); exit(1); } /* 开启一个 socket 监听 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { perror("socket"); system("pause"); exit(1); } else printf("socket createdn"); memset(&my_addr,0,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)) == -1) { perror("bind"); system("pause"); exit(1); } else printf("bindedn"); if (listen(sockfd, lisnum) == -1) { perror("listen"); system("pause"); exit(1); } else printf("begin listenn"); while (1) { SSL *ssl; len = sizeof(struct sockaddr); /* 等待客户端连上来 */ if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len))== -1) { perror("accept"); system("pause"); exit(errno); } else printf("server: got connection from %s, port %d, socket %dn", 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) == -1) { perror("accept"); close(new_fd); system("pause"); break; } ShowCerts(ssl); /* 开始处理每个新连接上的数据收发 */ //bzero(buf, MAXBUF + 1); memset(buf,0,MAXBUF + 1); strcpy(buf, "server->client"); /* 发消息给客户端 */ len = SSL_write(ssl, buf, strlen(buf)); if (len <= 0) { printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'n", buf, errno, strerror(errno)); goto finish; } else printf("消息'%s'发送成功,共发送了%d个字节!n", buf, len); memset(buf,0, MAXBUF + 1); /* 接收客户端的消息 */ len = SSL_read(ssl, buf, MAXBUF); if (len > 0) 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=-1; printf("服务端---请选择算法:n"); printf("1:RSA 2:SM2n"); scanf("%d",&alogType); if (alogType==1) { 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==2) { 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=-1; printf("服务端----请选择认证方式:n"); printf("1:单向认证 2:双向认证n"); scanf("%d",&type); switch (type) { case 1: One_Auth();break; case 2: Two_Auth();break; default: break; } system("pause"); return 0; }
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]={0}; //ca证书路径 char clientCertFilePath[MAX_PATH]={0}; //服务端证书路径 char clientPrivateFilePath[MAX_PATH]={0}; //服务端私钥路径 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), 0, 0); printf("证书: %sn", line); //free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("颁发者: %sn", line); //free(line); X509_free(cert); } else printf("无证书信息!n"); } void Auth_Two() { int sockfd, len; struct sockaddr_in dest; char buffer[MAXBUF + 1]; SSL_CTX *ctx; SSL *ssl; unsigned int myport; char *myip="127.0.0.1"; myport=7838; /*if (argc != 5) { printf("参数格式错误!正确用法如下:ntt%s IP地址 端口nt比如:t%s 127.0.0.1 80n此程序用来从某个" "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(1); } // 双向验证 // 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)<=0){ ERR_print_errors_fp(stdout); system("pause"); exit(1); } /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */ /* 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) <= 0) { ERR_print_errors_fp(stdout); system("pause"); exit(1); } /* 载入用户私钥 */ /*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) <= 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(2,2),&wsd); if(0 != resStartup) { printf("failed to WSAStartup!n"); system("pause"); exit(1); } /* 创建一个 socket 用于 tcp 通信 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket"); system("pause"); exit(errno); } printf("socket createdn"); /* 初始化服务器端(对方)的地址和端口信息 */ //bzero(&dest, sizeof(dest)); memset(&dest,0,sizeof(dest)); dest.sin_family = AF_INET; dest.sin_port = htons(myport); unsigned long l1=0; l1=inet_addr(myip); in_addr addr1; memcpy(&addr1, &l1, 4); if (inet_ntoa(addr1) == 0) { perror(myip); system("pause"); exit(errno); } dest.sin_addr=addr1; printf("address createdn"); /* 连接服务器 */ if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { perror("Connect "); system("pause"); exit(errno); } printf("server connectedn"); /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); SSL_set_fd(ssl, sockfd); /* 建立 SSL 连接 */ if (SSL_connect(ssl) == -1) ERR_print_errors_fp(stderr); else { printf("Connected with %s encryptionn", SSL_get_cipher(ssl)); ShowCerts(ssl); } /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */ memset(buffer,0, MAXBUF + 1); /* 接收服务器来的消息 */ len = SSL_read(ssl, buffer, MAXBUF); if (len > 0) printf("接收消息成功:'%s',共%d个字节的数据n", buffer, len); else { printf ("消息接收失败!错误代码是%d,错误信息是'%s'n", errno, strerror(errno)); goto finish; } memset(buffer,0, MAXBUF + 1); strcpy(buffer, "from client->server"); /* 发消息给服务器 */ len = SSL_write(ssl, buffer, strlen(buffer)); if (len < 0) 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 + 1]; SSL_CTX *ctx; SSL *ssl; unsigned int myport; char *myip="127.0.0.1"; myport=7838; /*if (argc != 5) { printf("参数格式错误!正确用法如下:ntt%s IP地址 端口nt比如:t%s 127.0.0.1 80n此程序用来从某个" "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(1); } // 单向验证 /*// 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(2,2),&wsd); if(0 != resStartup) { printf("failed to WSAStartup!n"); system("pause"); exit(1); } /* 创建一个 socket 用于 tcp 通信 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket"); system("pause"); exit(errno); } printf("socket createdn"); /* 初始化服务器端(对方)的地址和端口信息 */ //bzero(&dest, sizeof(dest)); memset(&dest,0,sizeof(dest)); dest.sin_family = AF_INET; dest.sin_port = htons(myport); unsigned long l1=0; l1=inet_addr(myip); in_addr addr1; memcpy(&addr1, &l1, 4); if (inet_ntoa(addr1) == 0) { perror(myip); system("pause"); exit(errno); } dest.sin_addr=addr1; printf("address createdn"); /* 连接服务器 */ if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { perror("Connect "); system("pause"); exit(errno); } printf("server connectedn"); /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); SSL_set_fd(ssl, sockfd); /* 建立 SSL 连接 */ if (SSL_connect(ssl) == -1) ERR_print_errors_fp(stderr); else { printf("Connected with %s encryptionn", SSL_get_cipher(ssl)); ShowCerts(ssl); } /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */ memset(buffer,0, MAXBUF + 1); /* 接收服务器来的消息 */ len = SSL_read(ssl, buffer, MAXBUF); if (len > 0) printf("接收消息成功:'%s',共%d个字节的数据n", buffer, len); else { printf ("消息接收失败!错误代码是%d,错误信息是'%s'n", errno, strerror(errno)); goto finish; } memset(buffer,0, MAXBUF + 1); strcpy(buffer, "from client->server"); /* 发消息给服务器 */ len = SSL_write(ssl, buffer, strlen(buffer)); if (len < 0) 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=-1; printf("客户端---请选择算法:n"); printf("1:RSA 2:SM2n"); scanf("%d",&alogType); if (alogType==1) { 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==2) { 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=-1; printf("客户端----请选择认证方式:n"); printf("1:单向认证 2:双向认证n"); scanf("%d",&type); switch (type) { case 1: Auth_One();break; case 2: Auth_Two();break; default: break; } system("pause"); return 0; }
以上代码RSA和ECC都测试通过了,但是SM2测试时候报错了。
45444:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:sslrecordrec_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:sslrecordrec_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
转载于:https://www.cnblogs.com/eaglexmw/p/11346492.html
最后
以上就是淡然棉花糖为你收集整理的[转载]OpenSSL身份认证 RSA、ECC、SM2的全部内容,希望文章能够帮你解决[转载]OpenSSL身份认证 RSA、ECC、SM2所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复