相关代码:
server端:
-
#include "stdafx.h"
- #include <winsock2.h>
- #include <conio.h>
- #include <stdio.h>
- #include "openssl/x509.h"
- #include "openssl/ssl.h"
- #include "openssl/err.h"
-
- #define MSGLENGTH 1024
- #define PORT 8888
- #define CACERT "./private/ca.crt"
- #define SVRCERTF "./certs/server.crt"
- #define SVRKEYF "./private/server.key"
-
- #pragma comment(lib, "wsock32.lib")
- #pragma comment(lib, "libeay32.lib")
- #pragma comment(lib, "ssleay32.lib")
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- WSADATA wsaData;
- WSAStartup(MAKEWORD(2,2), &wsaData);
- SOCKET sock;
- SSL_METHOD *meth;
- SSL_CTX* ctx;
- SSL* ssl;
- //SSL初始化
- OpenSSL_add_ssl_algorithms();
- //SSL错误信息初始化
- SSL_load_error_strings();
- //创建本次会话所使用的协议
- meth = (SSL_METHOD *)TLSv1_server_method();
- //申请SSL会话的环境
- ctx = SSL_CTX_new(meth);
- if (NULL == ctx)
- exit(1);
-
- //设置会话的握手方式并加载CA证书
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
- if (!SSL_CTX_load_verify_locations(ctx, CACERT, NULL))
- {
- printf("%d \n\n下载CA 证书出错!\n", SSL_CTX_load_verify_locations(ctx, CACERT, NULL));
- exit(-1);
- }
- //加载服务器端的证书
- if (!SSL_CTX_use_certificate_file(ctx, SVRCERTF, SSL_FILETYPE_PEM)) {
- ERR_print_errors_fp(stderr);
- exit(1);
- }
- //加载服务器端的私钥
- if (!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("\n\n私钥与证书公钥不匹配!\n");
- exit(1);
- }
-
- //加密方式
- SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
- //处理握手多次
- SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
-
- /*以下是正常的TCP socket建立过程.............................. */
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- printf("\n\nSOCKET有问题. \n");
- return 0;
- }
-
- 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;
-
- //绑定sock
- int nResult = bind(sock, (sockaddr *)&addr, sizeof(addr));
- if (nResult == SOCKET_ERROR) {
- printf("\n\n绑定SOCKET有问题.\n");
- return 0;
- }
- printf("\n**************************************\n");
- printf("\n服务器启动成功,端口:%d\n\n等待连接.....\n", PORT);
-
- /*接受TCP链接*/
- 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);
- }
- closesocket(sock);
- printf("\n连接端口:%d, port %d\n", sa_cli.sin_addr.s_addr, sa_cli.sin_port);
- /* TCP 链接已建立.开始SSL 握手过程.......................... */
- //绑定套接字
- ssl = SSL_new(ctx);
- if (NULL == ssl)
- exit(1);
- if (!SSL_set_fd(ssl, ss)) {
- printf("\n连接失败\n");
- exit(1);
- }
- //SSL握手
- //SSL_accept(ssl);
- int k = SSL_accept(ssl);
- if ( k != 1) {
- printf("%d\n", k);
- printf("\n连接失败\n");
- exit(1);
- }
- //进行信息验证
- X509 *client_cert;
- client_cert = SSL_get_peer_certificate(ssl);
-
- printf("\n发现客户端尝试连接\n");
- if (client_cert != NULL) {
- printf ("\n客服端证书:\n");
- //读取证书subject名并显示
- char *str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
- if (NULL == str) {
- printf("\n认证出错!\n");
- exit(1);
- }
- printf("\n主题:%s\n", str);
- //读取证书的issuer名并显示
- str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
- if (NULL == str) {
- printf("\n证书名为空\n");
- exit(1);
- }
- printf("\n颁发者:%s\n", str);
- printf("\n连接成功\n");
-
- X509_free (client_cert);/*如不再需要,需将证书释放*/
- OPENSSL_free(str);
- }
- else {
- printf("\n找不到客户端的认证证书\n");
- exit(1);
- }
-
- char buf[MSGLENGTH];
- SSL_write(ssl, "\n服务器连接成功!\n", strlen("\n服务器连接成功!\n"));
- printf("\n监听客服端:\n\n");
- while (1) {
- err = SSL_read(ssl, buf, sizeof(buf));
- buf[err] = '\0';
- if (!strcmp(buf, "退出"))
- {
- //关闭套接字
- SSL_shutdown(ssl);
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- WSACleanup();
- getchar();
- break;
- }
- else printf(">> %s\n", buf);
- }
-
- return 0;
- }
客户端代码:
- //client
- #include <winsock2.h>
- //#include <winsock.h>
- #include <conio.h>
- #include <stdio.h>
- #include "openssl/x509.h"
- #include "openssl/ssl.h"
- #include "openssl/err.h"
- #include "openssl/rand.h"
- #include <openssl/applink.c>
-
- #define PORT 8888
- #define SERVER "127.0.0.1"
- //#define SERVER "172.31.32.176"
- #define CACERT "./private/ca.crt"
- #define MYCERTF "./certs/client.crt"
- #define MYKEYF "./private/client.key"
- #define MSGLENGTH 1024
-
- #pragma comment(lib, "wsock32.lib")
- #pragma comment(lib, "libeay32.lib")
- #pragma comment(lib, "ssleay32.lib")
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- WSADATA wsadata;
- WSAStartup(MAKEWORD(2,2), &wsadata);
- sockaddr_in sin;
- int seed_int[100]; /*存放随机序列*/
-
- SSL *ssl;
- const SSL_METHOD *meth;
- SSL_CTX *ctx;
-
- //SSL初始化
- OpenSSL_add_ssl_algorithms();
- //SSL错误信息初始化
- SSL_load_error_strings();
-
- //创建本次会话所使用的协议
- meth = TLSv1_client_method();
- //申请SSL会话的环境
- ctx = SSL_CTX_new(meth);
- if (NULL == ctx)
- exit(1);
-
- //设置会话的握手方式并加载CA证书
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
- if (!SSL_CTX_load_verify_locations(ctx, CACERT, NULL))
- {
- printf("%d\n 下载CA 证书出错!\n", SSL_CTX_load_verify_locations(ctx, CACERT, NULL));
- exit(-1);
- }
-
- //加载自己的证书
- if (!SSL_CTX_use_certificate_file(ctx, MYCERTF, SSL_FILETYPE_PEM)) {
- ERR_print_errors_fp(stdout);
- printf("\n错误1 %d\n", SSL_CTX_use_certificate_file(ctx, MYCERTF, SSL_FILETYPE_PEM));
- exit(1);
- }
- //加载自己的私钥
- if (!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("\n私钥与证书公钥不匹配!\n");
- exit(1);
- }
-
- /*构建随机数生成机制,WIN32平台必需*/
- srand((unsigned)time(NULL));
- for (int 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);
-
- /*以下是正常的TCP socket建立过程.............................. */
- SOCKET sock;
- //printf("Begin tcp socket...\n");
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- printf("\nSOCKET有问题. \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, (sockaddr *)&sin, sizeof(sin));
- if (icnn == SOCKET_ERROR) {
- printf("\n连不上服务器\n", GetLastError());
- exit(1);
- }
-
- /* TCP 链接已建立.开始SSL 握手过程.......................... */
- //绑定套接字
- ssl = SSL_new(ctx);
- if (NULL == ssl)
- exit(1);
- if (0 >= SSL_set_fd(ssl, sock)) {
- printf("\n连接失败!\n");
- exit(1);
- }
- //SSL握手
- //SSL_connect(ssl);
- printf("\n正在连接服务器......\n");
- int k = SSL_connect(ssl);
- if (k != 1) {
- printf("%d\n", k);
- printf("\nSSL connect fail!\n");
- exit(1);
- }
- printf("\n连接服务器成功\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("\n请输入所要发送的数据:\n\n>> ");
- gets(sendmsg);
- SSL_write(ssl, sendmsg, strlen(sendmsg));
- printf("\n发送消息 %s 成功!\n", sendmsg);
- if (!strcmp(sendmsg, "exit"))
- {
- //关闭套接字
- //sleep(1);
- SSL_shutdown(ssl);
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- closesocket(sock);
- WSACleanup();
- getchar();
- break;
- }
- }
- return 0;
- }